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

Go to the source code of this file.

Data Structures

struct  socket_set
 
struct  Variable
 
struct  SimpleStats
 
struct  StatsData
 
struct  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 ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define 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  partition_method_t { PART_NONE, PART_RANGE, PART_HASH }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT, CSTATE_START_TX, CSTATE_PREPARE_THROTTLE, CSTATE_THROTTLE,
  CSTATE_START_COMMAND, CSTATE_WAIT_RESULT, CSTATE_SLEEP, CSTATE_END_COMMAND,
  CSTATE_SKIP_COMMAND, CSTATE_END_TX, CSTATE_ABORTED, CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE, META_SET, META_SETSHELL, META_SHELL,
  META_SLEEP, META_GSET, META_ASET, META_IF,
  META_ELIF, META_ELSE, META_ENDIF
}
 
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 append_fillfactor (char *opts, int len)
 
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, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (CState *st, int argc, char **argv, int *usecs)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static void disconnect_all (CState *state, int length)
 
static void initDropTables (PGconn *con)
 
static void createPartitions (PGconn *con)
 
static void initCreateTables (PGconn *con)
 
static void initTruncateTables (PGconn *con)
 
static void initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (ParsedScript ps)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printProgressReport (TState *threads, int64 test_start, 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
 
static int partitions = 0
 
static partition_method_t partition_method = PART_NONE
 
static const char * PARTITION_METHOD [] = {"none", "range", "hash"}
 
int64 random_seed = -1
 
bool use_log
 
bool use_quiet
 
int agg_interval
 
bool per_script_stats = false
 
int progress = 0
 
bool progress_timestamp = false
 
int nclients = 1
 
int nthreads = 1
 
bool is_connect
 
bool report_per_command
 
int main_pid
 
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 const BuiltinScript builtin_script []
 
static const PsqlScanCallbacks pgbench_callbacks
 

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

Definition at line 135 of file pgbench.c.

Referenced by checkInitSteps(), and usage().

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

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 138 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 79 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 78 of file pgbench.c.

Referenced by getHashFnv1a().

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 461 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

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

Definition at line 137 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 70 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 473 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1862 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2607 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 270 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 143 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 140 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 142 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 80 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 81 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 82 of file pgbench.c.

Referenced by getHashMurmur2().

◆ naccounts

#define naccounts   100000

◆ nbranches

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

Definition at line 215 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

Definition at line 217 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 54 of file pgbench.c.

◆ pthread_t

#define pthread_t   void *

Definition at line 127 of file pgbench.c.

Referenced by main(), and socket_has_input().

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 227 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 271 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 101 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ WSEP

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

Definition at line 249 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 316 of file pgbench.c.

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

◆ MetaCommand

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

Definition at line 475 of file pgbench.c.

476 {
477  META_NONE, /* not a known meta-command */
478  META_SET, /* \set */
479  META_SETSHELL, /* \setshell */
480  META_SHELL, /* \shell */
481  META_SLEEP, /* \sleep */
482  META_GSET, /* \gset */
483  META_ASET, /* \aset */
484  META_IF, /* \if */
485  META_ELIF, /* \elif */
486  META_ELSE, /* \else */
487  META_ENDIF /* \endif */
488 } MetaCommand;
MetaCommand
Definition: pgbench.c:475

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 198 of file pgbench.c.

199 {
200  PART_NONE, /* no partitioning */
201  PART_RANGE, /* range partitioning */
202  PART_HASH /* hash partitioning */
partition_method_t
Definition: pgbench.c:198

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 490 of file pgbench.c.

491 {
492  QUERY_SIMPLE, /* simple query */
493  QUERY_EXTENDED, /* extended query */
494  QUERY_PREPARED, /* extended query with prepared statements */
496 } QueryMode;
QueryMode
Definition: pgbench.c:490

Function Documentation

◆ accumStats()

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

Definition at line 1121 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1122 {
1123  stats->cnt++;
1124 
1125  if (skipped)
1126  {
1127  /* no latency to record on skipped transactions */
1128  stats->skipped++;
1129  }
1130  else
1131  {
1132  addToSimpleStats(&stats->latency, lat);
1133 
1134  /* and possibly the same for schedule lag */
1135  if (throttle_delay)
1136  addToSimpleStats(&stats->lag, lag);
1137  }
1138 }
SimpleStats lag
Definition: pgbench.c:299
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1077
SimpleStats latency
Definition: pgbench.c:298
double throttle_delay
Definition: pgbench.c:175
int64 cnt
Definition: pgbench.c:295
int64 skipped
Definition: pgbench.c:296

◆ add_socket_to_set()

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

Definition at line 6702 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6703 {
6704  if (fd < 0 || fd >= FD_SETSIZE)
6705  {
6706  /*
6707  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6708  * complicating the API to make it less grotty.
6709  */
6710  pg_log_fatal("too many client connections for select()");
6711  exit(1);
6712  }
6713  FD_SET(fd, &sa->fds);
6714  if (fd > sa->maxfd)
6715  sa->maxfd = fd;
6716 }
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:106
int maxfd
Definition: pgbench.c:105
#define pg_log_fatal(...)
Definition: logging.h:75

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5066 of file pgbench.c.

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

Referenced by ParseScript().

5067 {
5068  if (script.commands == NULL || script.commands[0] == NULL)
5069  {
5070  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5071  exit(1);
5072  }
5073 
5074  if (num_scripts >= MAX_SCRIPTS)
5075  {
5076  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5077  exit(1);
5078  }
5079 
5080  CheckConditional(script);
5081 
5082  sql_script[num_scripts] = script;
5083  num_scripts++;
5084 }
static int num_scripts
Definition: pgbench.c:543
#define MAX_SCRIPTS
Definition: pgbench.c:270
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4716
const char * desc
Definition: pgbench.c:536
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:542
Command ** commands
Definition: pgbench.c:538
#define pg_log_fatal(...)
Definition: logging.h:75

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1077 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1078 {
1079  if (ss->count == 0 || val < ss->min)
1080  ss->min = val;
1081  if (ss->count == 0 || val > ss->max)
1082  ss->max = val;
1083  ss->count++;
1084  ss->sum += val;
1085  ss->sum2 += val * val;
1086 }
double sum
Definition: pgbench.c:284
int64 count
Definition: pgbench.c:281
double max
Definition: pgbench.c:283
double sum2
Definition: pgbench.c:285
long val
Definition: informix.c:664
double min
Definition: pgbench.c:282

◆ advanceConnectionState()

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

Definition at line 2879 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(), 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(), pg_log_debug, pg_log_error, 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().

2880 {
2881  instr_time now;
2882 
2883  /*
2884  * gettimeofday() isn't free, so we get the current timestamp lazily the
2885  * first time it's needed, and reuse the same value throughout this
2886  * function after that. This also ensures that e.g. the calculated
2887  * latency reported in the log file and in the totals are the same. Zero
2888  * means "not set yet". Reset "now" when we execute shell commands or
2889  * expressions, which might take a non-negligible amount of time, though.
2890  */
2891  INSTR_TIME_SET_ZERO(now);
2892 
2893  /*
2894  * Loop in the state machine, until we have to wait for a result from the
2895  * server or have to sleep for throttling or \sleep.
2896  *
2897  * Note: In the switch-statement below, 'break' will loop back here,
2898  * meaning "continue in the state machine". Return is used to return to
2899  * the caller, giving the thread the opportunity to advance another
2900  * client.
2901  */
2902  for (;;)
2903  {
2904  Command *command;
2905 
2906  switch (st->state)
2907  {
2908  /* Select transaction (script) to run. */
2909  case CSTATE_CHOOSE_SCRIPT:
2910  st->use_file = chooseScript(thread);
2912 
2913  pg_log_debug("client %d executing script \"%s\"",
2914  st->id, sql_script[st->use_file].desc);
2915 
2916  /*
2917  * If time is over, we're done; otherwise, get ready to start
2918  * a new transaction, or to get throttled if that's requested.
2919  */
2922  break;
2923 
2924  /* Start new transaction (script) */
2925  case CSTATE_START_TX:
2926 
2927  /* establish connection if needed, i.e. under --connect */
2928  if (st->con == NULL)
2929  {
2930  instr_time start;
2931 
2933  start = now;
2934  if ((st->con = doConnect()) == NULL)
2935  {
2936  pg_log_error("client %d aborted while establishing connection", st->id);
2937  st->state = CSTATE_ABORTED;
2938  break;
2939  }
2941  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2942 
2943  /* Reset session-local state */
2944  memset(st->prepared, 0, sizeof(st->prepared));
2945  }
2946 
2947  /* record transaction start time */
2949  st->txn_begin = now;
2950 
2951  /*
2952  * When not throttling, this is also the transaction's
2953  * scheduled start time.
2954  */
2955  if (!throttle_delay)
2957 
2958  /* Begin with the first command */
2960  st->command = 0;
2961  break;
2962 
2963  /*
2964  * Handle throttling once per transaction by sleeping.
2965  */
2967 
2968  /*
2969  * Generate a delay such that the series of delays will
2970  * approximate a Poisson distribution centered on the
2971  * throttle_delay time.
2972  *
2973  * If transactions are too slow or a given wait is shorter
2974  * than a transaction, the next transaction will start right
2975  * away.
2976  */
2977  Assert(throttle_delay > 0);
2978 
2979  thread->throttle_trigger +=
2981  st->txn_scheduled = thread->throttle_trigger;
2982 
2983  /*
2984  * If --latency-limit is used, and this slot is already late
2985  * so that the transaction will miss the latency limit even if
2986  * it completed immediately, skip this time slot and schedule
2987  * to continue running on the next slot that isn't late yet.
2988  * But don't iterate beyond the -t limit, if one is given.
2989  */
2990  if (latency_limit)
2991  {
2992  int64 now_us;
2993 
2995  now_us = INSTR_TIME_GET_MICROSEC(now);
2996 
2997  while (thread->throttle_trigger < now_us - latency_limit &&
2998  (nxacts <= 0 || st->cnt < nxacts))
2999  {
3000  processXactStats(thread, st, &now, true, agg);
3001  /* next rendez-vous */
3002  thread->throttle_trigger +=
3004  st->txn_scheduled = thread->throttle_trigger;
3005  }
3006 
3007  /*
3008  * stop client if -t was exceeded in the previous skip
3009  * loop
3010  */
3011  if (nxacts > 0 && st->cnt >= nxacts)
3012  {
3013  st->state = CSTATE_FINISHED;
3014  break;
3015  }
3016  }
3017 
3018  /*
3019  * stop client if next transaction is beyond pgbench end of
3020  * execution; otherwise, throttle it.
3021  */
3022  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3024  break;
3025 
3026  /*
3027  * Wait until it's time to start next transaction.
3028  */
3029  case CSTATE_THROTTLE:
3031 
3032  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
3033  return; /* still sleeping, nothing to do here */
3034 
3035  /* done sleeping, but don't start transaction if we're done */
3037  break;
3038 
3039  /*
3040  * Send a command to server (or execute a meta-command)
3041  */
3042  case CSTATE_START_COMMAND:
3043  command = sql_script[st->use_file].commands[st->command];
3044 
3045  /* Transition to script end processing if done */
3046  if (command == NULL)
3047  {
3048  st->state = CSTATE_END_TX;
3049  break;
3050  }
3051 
3052  /* record begin time of next command, and initiate it */
3053  if (report_per_command)
3054  {
3056  st->stmt_begin = now;
3057  }
3058 
3059  /* Execute the command */
3060  if (command->type == SQL_COMMAND)
3061  {
3062  if (!sendCommand(st, command))
3063  {
3064  commandFailed(st, "SQL", "SQL command send failed");
3065  st->state = CSTATE_ABORTED;
3066  }
3067  else
3068  st->state = CSTATE_WAIT_RESULT;
3069  }
3070  else if (command->type == META_COMMAND)
3071  {
3072  /*-----
3073  * Possible state changes when executing meta commands:
3074  * - on errors CSTATE_ABORTED
3075  * - on sleep CSTATE_SLEEP
3076  * - else CSTATE_END_COMMAND
3077  */
3078  st->state = executeMetaCommand(st, &now);
3079  }
3080 
3081  /*
3082  * We're now waiting for an SQL command to complete, or
3083  * finished processing a metacommand, or need to sleep, or
3084  * something bad happened.
3085  */
3086  Assert(st->state == CSTATE_WAIT_RESULT ||
3087  st->state == CSTATE_END_COMMAND ||
3088  st->state == CSTATE_SLEEP ||
3089  st->state == CSTATE_ABORTED);
3090  break;
3091 
3092  /*
3093  * non executed conditional branch
3094  */
3095  case CSTATE_SKIP_COMMAND:
3097  /* quickly skip commands until something to do... */
3098  while (true)
3099  {
3100  Command *command;
3101 
3102  command = sql_script[st->use_file].commands[st->command];
3103 
3104  /* cannot reach end of script in that state */
3105  Assert(command != NULL);
3106 
3107  /*
3108  * if this is conditional related, update conditional
3109  * state
3110  */
3111  if (command->type == META_COMMAND &&
3112  (command->meta == META_IF ||
3113  command->meta == META_ELIF ||
3114  command->meta == META_ELSE ||
3115  command->meta == META_ENDIF))
3116  {
3117  switch (conditional_stack_peek(st->cstack))
3118  {
3119  case IFSTATE_FALSE:
3120  if (command->meta == META_IF ||
3121  command->meta == META_ELIF)
3122  {
3123  /* we must evaluate the condition */
3125  }
3126  else if (command->meta == META_ELSE)
3127  {
3128  /* we must execute next command */
3132  st->command++;
3133  }
3134  else if (command->meta == META_ENDIF)
3135  {
3138  if (conditional_active(st->cstack))
3140 
3141  /*
3142  * else state remains in
3143  * CSTATE_SKIP_COMMAND
3144  */
3145  st->command++;
3146  }
3147  break;
3148 
3149  case IFSTATE_IGNORED:
3150  case IFSTATE_ELSE_FALSE:
3151  if (command->meta == META_IF)
3153  IFSTATE_IGNORED);
3154  else if (command->meta == META_ENDIF)
3155  {
3158  if (conditional_active(st->cstack))
3160  }
3161  /* could detect "else" & "elif" after "else" */
3162  st->command++;
3163  break;
3164 
3165  case IFSTATE_NONE:
3166  case IFSTATE_TRUE:
3167  case IFSTATE_ELSE_TRUE:
3168  default:
3169 
3170  /*
3171  * inconsistent if inactive, unreachable dead
3172  * code
3173  */
3174  Assert(false);
3175  }
3176  }
3177  else
3178  {
3179  /* skip and consider next */
3180  st->command++;
3181  }
3182 
3183  if (st->state != CSTATE_SKIP_COMMAND)
3184  /* out of quick skip command loop */
3185  break;
3186  }
3187  break;
3188 
3189  /*
3190  * Wait for the current SQL command to complete
3191  */
3192  case CSTATE_WAIT_RESULT:
3193  pg_log_debug("client %d receiving", st->id);
3194  if (!PQconsumeInput(st->con))
3195  {
3196  /* there's something wrong */
3197  commandFailed(st, "SQL", "perhaps the backend died while processing");
3198  st->state = CSTATE_ABORTED;
3199  break;
3200  }
3201  if (PQisBusy(st->con))
3202  return; /* don't have the whole result yet */
3203 
3204  /* store or discard the query results */
3205  if (readCommandResponse(st,
3208  st->state = CSTATE_END_COMMAND;
3209  else
3210  st->state = CSTATE_ABORTED;
3211  break;
3212 
3213  /*
3214  * Wait until sleep is done. This state is entered after a
3215  * \sleep metacommand. The behavior is similar to
3216  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3217  * instead of CSTATE_START_TX.
3218  */
3219  case CSTATE_SLEEP:
3221  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
3222  return; /* still sleeping, nothing to do here */
3223  /* Else done sleeping. */
3224  st->state = CSTATE_END_COMMAND;
3225  break;
3226 
3227  /*
3228  * End of command: record stats and proceed to next command.
3229  */
3230  case CSTATE_END_COMMAND:
3231 
3232  /*
3233  * command completed: accumulate per-command execution times
3234  * in thread-local data structure, if per-command latencies
3235  * are requested.
3236  */
3237  if (report_per_command)
3238  {
3239  Command *command;
3240 
3242 
3243  command = sql_script[st->use_file].commands[st->command];
3244  /* XXX could use a mutex here, but we choose not to */
3245  addToSimpleStats(&command->stats,
3246  INSTR_TIME_GET_DOUBLE(now) -
3248  }
3249 
3250  /* Go ahead with next command, to be executed or skipped */
3251  st->command++;
3252  st->state = conditional_active(st->cstack) ?
3254  break;
3255 
3256  /*
3257  * End of transaction (end of script, really).
3258  */
3259  case CSTATE_END_TX:
3260 
3261  /* transaction finished: calculate latency and do log */
3262  processXactStats(thread, st, &now, false, agg);
3263 
3264  /*
3265  * missing \endif... cannot happen if CheckConditional was
3266  * okay
3267  */
3269 
3270  if (is_connect)
3271  {
3272  finishCon(st);
3273  INSTR_TIME_SET_ZERO(now);
3274  }
3275 
3276  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3277  {
3278  /* script completed */
3279  st->state = CSTATE_FINISHED;
3280  break;
3281  }
3282 
3283  /* next transaction (script) */
3285 
3286  /*
3287  * Ensure that we always return on this point, so as to avoid
3288  * an infinite loop if the script only contains meta commands.
3289  */
3290  return;
3291 
3292  /*
3293  * Final states. Close the connection if it's still open.
3294  */
3295  case CSTATE_ABORTED:
3296  case CSTATE_FINISHED:
3297  finishCon(st);
3298  return;
3299  }
3300  }
3301 }
int64 throttle_trigger
Definition: pgbench.c:451
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
int type
Definition: pgbench.c:525
int id
Definition: pgbench.c:401
static int chooseScript(TState *thread)
Definition: pgbench.c:2623
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
#define pg_log_error(...)
Definition: logging.h:79
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:2615
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:1077
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
int duration
Definition: pgbench.c:146
ConditionalStack cstack
Definition: pgbench.c:403
static void finishCon(CState *st)
Definition: pgbench.c:6515
bool is_connect
Definition: pgbench.c:238
double throttle_delay
Definition: pgbench.c:175
int64 end_time
Definition: pgbench.c:147
instr_time stmt_begin
Definition: pgbench.c:423
static ConnectionStateEnum executeMetaCommand(CState *st, instr_time *now)
Definition: pgbench.c:3311
#define META_COMMAND
Definition: pgbench.c:467
#define pg_log_debug(...)
Definition: logging.h:91
int nxacts
Definition: pgbench.c:145
const char * desc
Definition: pgbench.c:536
int64 cnt
Definition: pgbench.c:428
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:2725
MetaCommand meta
Definition: pgbench.c:526
int64 txn_scheduled
Definition: pgbench.c:420
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:542
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2642
RandomState ts_throttle_rs
Definition: pgbench.c:448
instr_time txn_begin
Definition: pgbench.c:422
#define SQL_COMMAND
Definition: pgbench.c:466
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1704
int command
Definition: pgbench.c:412
SimpleStats stats
Definition: pgbench.c:531
ConnectionStateEnum state
Definition: pgbench.c:402
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:421
PGconn * con
Definition: pgbench.c:400
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
static PGconn * doConnect(void)
Definition: pgbench.c:1173
#define Assert(condition)
Definition: c.h:738
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:1754
#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:529
volatile bool timer_exceeded
Definition: pgbench.c:251
Command ** commands
Definition: pgbench.c:538
int64 latency_limit
Definition: pgbench.c:183
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
bool report_per_command
Definition: pgbench.c:239
static int64 getPoissonRand(RandomState *random_state, double center)
Definition: pgbench.c:954
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:118
instr_time conn_time
Definition: pgbench.c:456
bool prepared[MAX_SCRIPTS]
Definition: pgbench.c:425
static void processXactStats(TState *thread, CState *st, instr_time *now, bool skipped, StatsData *agg)
Definition: pgbench.c:3552
int use_file
Definition: pgbench.c:411
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6683 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6684 {
6685  return (socket_set *) pg_malloc0(sizeof(socket_set));
6686 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ append_fillfactor()

static void append_fillfactor ( char *  opts,
int  len 
)
static

Definition at line 3798 of file pgbench.c.

References snprintf.

Referenced by createPartitions(), and initCreateTables().

3799 {
3800  snprintf(opts + strlen(opts), len - strlen(opts),
3801  " with (fillfactor=%d)", fillfactor);
3802 }
int fillfactor
Definition: pgbench.c:159
#define snprintf
Definition: port.h:193

◆ assignVariables()

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

Definition at line 1557 of file pgbench.c.

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

Referenced by sendCommand().

1558 {
1559  char *p,
1560  *name,
1561  *val;
1562 
1563  p = sql;
1564  while ((p = strchr(p, ':')) != NULL)
1565  {
1566  int eaten;
1567 
1568  name = parseVariable(p, &eaten);
1569  if (name == NULL)
1570  {
1571  while (*p == ':')
1572  {
1573  p++;
1574  }
1575  continue;
1576  }
1577 
1578  val = getVariable(st, name);
1579  free(name);
1580  if (val == NULL)
1581  {
1582  p++;
1583  continue;
1584  }
1585 
1586  p = replaceVariable(&sql, p, eaten, val);
1587  }
1588 
1589  return sql;
1590 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1276
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1537
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1514
const char * name
Definition: encode.c:555
long val
Definition: informix.c:664

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

Definition at line 4716 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().

4717 {
4718  /* statically check conditional structure */
4720  int i;
4721 
4722  for (i = 0; ps.commands[i] != NULL; i++)
4723  {
4724  Command *cmd = ps.commands[i];
4725 
4726  if (cmd->type == META_COMMAND)
4727  {
4728  switch (cmd->meta)
4729  {
4730  case META_IF:
4732  break;
4733  case META_ELIF:
4734  if (conditional_stack_empty(cs))
4735  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4737  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4738  break;
4739  case META_ELSE:
4740  if (conditional_stack_empty(cs))
4741  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4743  ConditionError(ps.desc, i + 1, "\\else after \\else");
4745  break;
4746  case META_ENDIF:
4747  if (!conditional_stack_pop(cs))
4748  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4749  break;
4750  default:
4751  /* ignore anything else... */
4752  break;
4753  }
4754  }
4755  }
4756  if (!conditional_stack_empty(cs))
4757  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4759 }
int type
Definition: pgbench.c:525
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4705
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:467
const char * desc
Definition: pgbench.c:536
MetaCommand meta
Definition: pgbench.c:526
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:538
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 4080 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4081 {
4082  if (initialize_steps[0] == '\0')
4083  {
4084  pg_log_fatal("no initialization steps specified");
4085  exit(1);
4086  }
4087 
4088  for (const char *step = initialize_steps; *step != '\0'; step++)
4089  {
4090  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4091  {
4092  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4093  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4094  exit(1);
4095  }
4096  }
4097 }
#define ALL_INIT_STEPS
Definition: pgbench.c:135
#define pg_log_info(...)
Definition: logging.h:87
#define pg_log_fatal(...)
Definition: logging.h:75

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2623 of file pgbench.c.

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

Referenced by advanceConnectionState().

2624 {
2625  int i = 0;
2626  int64 w;
2627 
2628  if (num_scripts == 1)
2629  return 0;
2630 
2631  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2632  do
2633  {
2634  w -= sql_script[i++].weight;
2635  } while (w >= 0);
2636 
2637  return i - 1;
2638 }
static int num_scripts
Definition: pgbench.c:543
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:850
int weight
Definition: pgbench.c:537
RandomState ts_choose_rs
Definition: pgbench.c:447
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:542
static int64 total_weight
Definition: pgbench.c:544
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6695 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6696 {
6697  FD_ZERO(&sa->fds);
6698  sa->maxfd = -1;
6699 }
fd_set fds
Definition: pgbench.c:106
int maxfd
Definition: pgbench.c:105

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1624 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1625 {
1626  if (pval->type == PGBT_BOOLEAN)
1627  {
1628  *bval = pval->u.bval;
1629  return true;
1630  }
1631  else /* NULL, INT or DOUBLE */
1632  {
1633  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1634  *bval = false; /* suppress uninitialized-variable warnings */
1635  return false;
1636  }
1637 }
#define pg_log_error(...)
Definition: logging.h:79
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1602
union PgBenchValue::@38 u
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

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

Definition at line 1693 of file pgbench.c.

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

Referenced by evalStandardFunc().

1694 {
1695  if (pval->type == PGBT_DOUBLE)
1696  {
1697  *dval = pval->u.dval;
1698  return true;
1699  }
1700  else if (pval->type == PGBT_INT)
1701  {
1702  *dval = (double) pval->u.ival;
1703  return true;
1704  }
1705  else /* BOOLEAN or NULL */
1706  {
1707  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1708  return false;
1709  }
1710 }
#define pg_log_error(...)
Definition: logging.h:79
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1602
union PgBenchValue::@38 u
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 1665 of file pgbench.c.

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

Referenced by evalStandardFunc().

1666 {
1667  if (pval->type == PGBT_INT)
1668  {
1669  *ival = pval->u.ival;
1670  return true;
1671  }
1672  else if (pval->type == PGBT_DOUBLE)
1673  {
1674  double dval = rint(pval->u.dval);
1675 
1676  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1677  {
1678  pg_log_error("double to int overflow for %f", dval);
1679  return false;
1680  }
1681  *ival = (int64) dval;
1682  return true;
1683  }
1684  else /* BOOLEAN or NULL */
1685  {
1686  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1687  return false;
1688  }
1689 }
#define pg_log_error(...)
Definition: logging.h:79
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1070
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1602
union PgBenchValue::@38 u
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 2615 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2616 {
2617  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2618  st->id, st->command, cmd, st->use_file, message);
2619 }
int id
Definition: pgbench.c:401
#define pg_log_error(...)
Definition: logging.h:79
int command
Definition: pgbench.c:412
int use_file
Definition: pgbench.c:411

◆ compareVariableNames()

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

Definition at line 1241 of file pgbench.c.

References name.

Referenced by lookupVariable().

1242 {
1243  return strcmp(((const Variable *) v1)->name,
1244  ((const Variable *) v2)->name);
1245 }
const char * name
Definition: encode.c:555

◆ computeIterativeZipfian()

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

Definition at line 976 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

977 {
978  double b = pow(2.0, s - 1.0);
979  double x,
980  t,
981  u,
982  v;
983 
984  /* Ensure n is sane */
985  if (n <= 1)
986  return 1;
987 
988  while (true)
989  {
990  /* random variates */
991  u = pg_erand48(random_state->xseed);
992  v = pg_erand48(random_state->xseed);
993 
994  x = floor(pow(u, -1.0 / (s - 1.0)));
995 
996  t = pow(1.0 + 1.0 / x, s - 1.0);
997  /* reject if too large or out of bound */
998  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
999  break;
1000  }
1001  return (int64) x;
1002 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:307

◆ ConditionError()

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

Definition at line 4705 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

4706 {
4707  pg_log_fatal("condition error in script \"%s\" command %d: %s",
4708  desc, cmdn, msg);
4709  exit(1);
4710 }
#define pg_log_fatal(...)
Definition: logging.h:75

◆ create_sql_command()

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

Definition at line 4440 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().

4441 {
4442  Command *my_command;
4443  char *p = skip_sql_comments(buf->data);
4444 
4445  if (p == NULL)
4446  return NULL;
4447 
4448  /* Allocate and initialize Command structure */
4449  my_command = (Command *) pg_malloc(sizeof(Command));
4450  initPQExpBuffer(&my_command->lines);
4451  appendPQExpBufferStr(&my_command->lines, p);
4452  my_command->first_line = NULL; /* this is set later */
4453  my_command->type = SQL_COMMAND;
4454  my_command->meta = META_NONE;
4455  my_command->argc = 0;
4456  memset(my_command->argv, 0, sizeof(my_command->argv));
4457  my_command->varprefix = NULL; /* allocated later, if needed */
4458  my_command->expr = NULL;
4459  initSimpleStats(&my_command->stats);
4460 
4461  return my_command;
4462 }
int type
Definition: pgbench.c:525
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:530
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4405
char * argv[MAX_ARGS]
Definition: pgbench.c:528
MetaCommand meta
Definition: pgbench.c:526
PQExpBufferData lines
Definition: pgbench.c:523
int argc
Definition: pgbench.c:527
#define SQL_COMMAND
Definition: pgbench.c:466
SimpleStats stats
Definition: pgbench.c:531
char * varprefix
Definition: pgbench.c:529
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1068
char * first_line
Definition: pgbench.c:524
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3632 of file pgbench.c.

References append_fillfactor(), Assert, executeStatement(), fprintf, INT64_FORMAT, naccounts, PART_HASH, PART_RANGE, partitions, snprintf, and sprintf.

Referenced by initCreateTables().

3633 {
3634  char ff[64];
3635 
3636  ff[0] = '\0';
3637 
3638  /*
3639  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3640  * pgbench_accounts.
3641  */
3642  append_fillfactor(ff, sizeof(ff));
3643 
3644  /* we must have to create some partitions */
3645  Assert(partitions > 0);
3646 
3647  fprintf(stderr, "creating %d partitions...\n", partitions);
3648 
3649  for (int p = 1; p <= partitions; p++)
3650  {
3651  char query[256];
3652 
3654  {
3655  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3656  char minvalue[32],
3657  maxvalue[32];
3658 
3659  /*
3660  * For RANGE, we use open-ended partitions at the beginning and
3661  * end to allow any valid value for the primary key. Although the
3662  * actual minimum and maximum values can be derived from the
3663  * scale, it is more generic and the performance is better.
3664  */
3665  if (p == 1)
3666  sprintf(minvalue, "minvalue");
3667  else
3668  sprintf(minvalue, INT64_FORMAT, (p - 1) * part_size + 1);
3669 
3670  if (p < partitions)
3671  sprintf(maxvalue, INT64_FORMAT, p * part_size + 1);
3672  else
3673  sprintf(maxvalue, "maxvalue");
3674 
3675  snprintf(query, sizeof(query),
3676  "create%s table pgbench_accounts_%d\n"
3677  " partition of pgbench_accounts\n"
3678  " for values from (%s) to (%s)%s\n",
3679  unlogged_tables ? " unlogged" : "", p,
3680  minvalue, maxvalue, ff);
3681  }
3682  else if (partition_method == PART_HASH)
3683  snprintf(query, sizeof(query),
3684  "create%s table pgbench_accounts_%d\n"
3685  " partition of pgbench_accounts\n"
3686  " for values with (modulus %d, remainder %d)%s\n",
3687  unlogged_tables ? " unlogged" : "", p,
3688  partitions, p - 1, ff);
3689  else /* cannot get there */
3690  Assert(0);
3691 
3692  executeStatement(con, query);
3693  }
3694 }
static int partitions
Definition: pgbench.c:195
static partition_method_t partition_method
Definition: pgbench.c:205
int scale
Definition: pgbench.c:153
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define sprintf
Definition: port.h:195
static void append_fillfactor(char *opts, int len)
Definition: pgbench.c:3798
#define naccounts
Definition: pgbench.c:218
#define Assert(condition)
Definition: c.h:738
#define INT64_FORMAT
Definition: c.h:409
bool unlogged_tables
Definition: pgbench.c:164
#define snprintf
Definition: port.h:193

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3598 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3599 {
3600  int i;
3601 
3602  for (i = 0; i < length; i++)
3603  finishCon(&state[i]);
3604 }
static void finishCon(CState *st)
Definition: pgbench.c:6515
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1173 of file pgbench.c.

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

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

1174 {
1175  PGconn *conn;
1176  bool new_pass;
1177  static bool have_password = false;
1178  static char password[100];
1179 
1180  /*
1181  * Start the connection. Loop until we have a password if requested by
1182  * backend.
1183  */
1184  do
1185  {
1186 #define PARAMS_ARRAY_SIZE 7
1187 
1188  const char *keywords[PARAMS_ARRAY_SIZE];
1189  const char *values[PARAMS_ARRAY_SIZE];
1190 
1191  keywords[0] = "host";
1192  values[0] = pghost;
1193  keywords[1] = "port";
1194  values[1] = pgport;
1195  keywords[2] = "user";
1196  values[2] = login;
1197  keywords[3] = "password";
1198  values[3] = have_password ? password : NULL;
1199  keywords[4] = "dbname";
1200  values[4] = dbName;
1201  keywords[5] = "fallback_application_name";
1202  values[5] = progname;
1203  keywords[6] = NULL;
1204  values[6] = NULL;
1205 
1206  new_pass = false;
1207 
1208  conn = PQconnectdbParams(keywords, values, true);
1209 
1210  if (!conn)
1211  {
1212  pg_log_error("connection to database \"%s\" failed", dbName);
1213  return NULL;
1214  }
1215 
1216  if (PQstatus(conn) == CONNECTION_BAD &&
1217  PQconnectionNeedsPassword(conn) &&
1218  !have_password)
1219  {
1220  PQfinish(conn);
1221  simple_prompt("Password: ", password, sizeof(password), false);
1222  have_password = true;
1223  new_pass = true;
1224  }
1225  } while (new_pass);
1226 
1227  /* check to see that the backend connection was successfully made */
1228  if (PQstatus(conn) == CONNECTION_BAD)
1229  {
1230  pg_log_error("connection to database \"%s\" failed: %s",
1231  dbName, PQerrorMessage(conn));
1232  PQfinish(conn);
1233  return NULL;
1234  }
1235 
1236  return conn;
1237 }
static char password[100]
Definition: streamutil.c:53
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6687
#define pg_log_error(...)
Definition: logging.h:79
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4185
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:640
PGconn * conn
Definition: streamutil.c:54
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:242
static bool have_password
Definition: streamutil.c:52
const char * progname
Definition: pgbench.c:247
static Datum values[MAXATTR]
Definition: bootstrap.c:167
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6721
char * dbName
Definition: pgbench.c:245
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6634
char * pgport
Definition: pgbench.c:243
char * login
Definition: pgbench.c:244

◆ doLog()

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

Definition at line 3471 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().

3473 {
3474  FILE *logfile = thread->logfile;
3475 
3476  Assert(use_log);
3477 
3478  /*
3479  * Skip the log entry if sampling is enabled and this row doesn't belong
3480  * to the random sample.
3481  */
3482  if (sample_rate != 0.0 &&
3484  return;
3485 
3486  /* should we aggregate the results or not? */
3487  if (agg_interval > 0)
3488  {
3489  /*
3490  * Loop until we reach the interval of the current moment, and print
3491  * any empty intervals in between (this may happen with very low tps,
3492  * e.g. --rate=0.1).
3493  */
3494  time_t now = time(NULL);
3495 
3496  while (agg->start_time + agg_interval <= now)
3497  {
3498  /* print aggregated report to logfile */
3499  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3500  (long) agg->start_time,
3501  agg->cnt,
3502  agg->latency.sum,
3503  agg->latency.sum2,
3504  agg->latency.min,
3505  agg->latency.max);
3506  if (throttle_delay)
3507  {
3508  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3509  agg->lag.sum,
3510  agg->lag.sum2,
3511  agg->lag.min,
3512  agg->lag.max);
3513  if (latency_limit)
3514  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3515  }
3516  fputc('\n', logfile);
3517 
3518  /* reset data and move to next interval */
3519  initStats(agg, agg->start_time + agg_interval);
3520  }
3521 
3522  /* accumulate the current transaction */
3523  accumStats(agg, skipped, latency, lag);
3524  }
3525  else
3526  {
3527  /* no, print raw transactions */
3528  struct timeval tv;
3529 
3530  gettimeofday(&tv, NULL);
3531  if (skipped)
3532  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
3533  st->id, st->cnt, st->use_file,
3534  (long) tv.tv_sec, (long) tv.tv_usec);
3535  else
3536  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
3537  st->id, st->cnt, latency, st->use_file,
3538  (long) tv.tv_sec, (long) tv.tv_usec);
3539  if (throttle_delay)
3540  fprintf(logfile, " %.0f", lag);
3541  fputc('\n', logfile);
3542  }
3543 }
time_t start_time
Definition: pgbench.c:294
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:104
double sample_rate
Definition: pgbench.c:169
int id
Definition: pgbench.c:401
SimpleStats lag
Definition: pgbench.c:299
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:1108
double sum
Definition: pgbench.c:284
RandomState ts_sample_rs
Definition: pgbench.c:449
bool use_log
Definition: pgbench.c:229
static FILE * logfile
Definition: pg_regress.c:100
SimpleStats latency
Definition: pgbench.c:298
#define fprintf
Definition: port.h:197
double throttle_delay
Definition: pgbench.c:175
FILE * logfile
Definition: pgbench.c:452
int64 cnt
Definition: pgbench.c:295
int64 cnt
Definition: pgbench.c:428
int64 skipped
Definition: pgbench.c:296
double max
Definition: pgbench.c:283
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1121
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:738
double sum2
Definition: pgbench.c:285
unsigned short xseed[3]
Definition: pgbench.c:307
int64 latency_limit
Definition: pgbench.c:183
#define INT64_FORMAT
Definition: c.h:409
int use_file
Definition: pgbench.c:411
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547
double min
Definition: pgbench.c:282
int agg_interval
Definition: pgbench.c:231

◆ evalFunc()

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

Definition at line 2411 of file pgbench.c.

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

Referenced by evaluateExpr().

2413 {
2414  if (isLazyFunc(func))
2415  return evalLazyFunc(st, func, args, retval);
2416  else
2417  return evalStandardFunc(st, func, args, retval);
2418 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1752
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1869
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1745

◆ evalLazyFunc()

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

Definition at line 1752 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().

1754 {
1755  PgBenchValue a1,
1756  a2;
1757  bool ba1,
1758  ba2;
1759 
1760  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1761 
1762  /* args points to first condition */
1763  if (!evaluateExpr(st, args->expr, &a1))
1764  return false;
1765 
1766  /* second condition for AND/OR and corresponding branch for CASE */
1767  args = args->next;
1768 
1769  switch (func)
1770  {
1771  case PGBENCH_AND:
1772  if (a1.type == PGBT_NULL)
1773  {
1774  setNullValue(retval);
1775  return true;
1776  }
1777 
1778  if (!coerceToBool(&a1, &ba1))
1779  return false;
1780 
1781  if (!ba1)
1782  {
1783  setBoolValue(retval, false);
1784  return true;
1785  }
1786 
1787  if (!evaluateExpr(st, args->expr, &a2))
1788  return false;
1789 
1790  if (a2.type == PGBT_NULL)
1791  {
1792  setNullValue(retval);
1793  return true;
1794  }
1795  else if (!coerceToBool(&a2, &ba2))
1796  return false;
1797  else
1798  {
1799  setBoolValue(retval, ba2);
1800  return true;
1801  }
1802 
1803  return true;
1804 
1805  case PGBENCH_OR:
1806 
1807  if (a1.type == PGBT_NULL)
1808  {
1809  setNullValue(retval);
1810  return true;
1811  }
1812 
1813  if (!coerceToBool(&a1, &ba1))
1814  return false;
1815 
1816  if (ba1)
1817  {
1818  setBoolValue(retval, true);
1819  return true;
1820  }
1821 
1822  if (!evaluateExpr(st, args->expr, &a2))
1823  return false;
1824 
1825  if (a2.type == PGBT_NULL)
1826  {
1827  setNullValue(retval);
1828  return true;
1829  }
1830  else if (!coerceToBool(&a2, &ba2))
1831  return false;
1832  else
1833  {
1834  setBoolValue(retval, ba2);
1835  return true;
1836  }
1837 
1838  case PGBENCH_CASE:
1839  /* when true, execute branch */
1840  if (valueTruth(&a1))
1841  return evaluateExpr(st, args->expr, retval);
1842 
1843  /* now args contains next condition or final else expression */
1844  args = args->next;
1845 
1846  /* final else case? */
1847  if (args->next == NULL)
1848  return evaluateExpr(st, args->expr, retval);
1849 
1850  /* no, another when, proceed */
1851  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
1852 
1853  default:
1854  /* internal error, cannot get here */
1855  Assert(0);
1856  break;
1857  }
1858  return false;
1859 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1624
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1752
static const FormData_pg_attribute a2
Definition: heap.c:165
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2427
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1722
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1714
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1745
#define Assert(condition)
Definition: c.h:738
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1644
PgBenchValueType type
Definition: pgbench.h:46
static const FormData_pg_attribute a1
Definition: heap.c:151

◆ evalStandardFunc()

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

Definition at line 1869 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_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_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().

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

◆ evaluateExpr()

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

Definition at line 2427 of file pgbench.c.

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

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

2428 {
2429  switch (expr->etype)
2430  {
2431  case ENODE_CONSTANT:
2432  {
2433  *retval = expr->u.constant;
2434  return true;
2435  }
2436 
2437  case ENODE_VARIABLE:
2438  {
2439  Variable *var;
2440 
2441  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2442  {
2443  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2444  return false;
2445  }
2446 
2447  if (!makeVariableValue(var))
2448  return false;
2449 
2450  *retval = var->value;
2451  return true;
2452  }
2453 
2454  case ENODE_FUNCTION:
2455  return evalFunc(st,
2456  expr->u.function.function,
2457  expr->u.function.args,
2458  retval);
2459 
2460  default:
2461  /* internal error which should never occur */
2462  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2463  exit(1);
2464  }
2465 }
PgBenchValue constant
Definition: pgbench.h:114
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1249
#define pg_log_error(...)
Definition: logging.h:79
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2411
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1309
PgBenchValue value
Definition: pgbench.c:267
struct PgBenchExpr::@39::@40 variable
PgBenchFunction function
Definition: pgbench.h:121
union PgBenchExpr::@39 u
PgBenchExprType etype
Definition: pgbench.h:111
#define pg_log_fatal(...)
Definition: logging.h:75

◆ evaluateSleep()

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

Definition at line 2844 of file pgbench.c.

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

Referenced by executeMetaCommand().

2845 {
2846  char *var;
2847  int usec;
2848 
2849  if (*argv[1] == ':')
2850  {
2851  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2852  {
2853  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
2854  return false;
2855  }
2856  usec = atoi(var);
2857  }
2858  else
2859  usec = atoi(argv[1]);
2860 
2861  if (argc > 2)
2862  {
2863  if (pg_strcasecmp(argv[2], "ms") == 0)
2864  usec *= 1000;
2865  else if (pg_strcasecmp(argv[2], "s") == 0)
2866  usec *= 1000000;
2867  }
2868  else
2869  usec *= 1000000;
2870 
2871  *usecs = usec;
2872  return true;
2873 }
#define pg_log_error(...)
Definition: logging.h:79
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1276
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
instr_time now 
)
static

Definition at line 3311 of file pgbench.c.

References __pg_log_level, appendPQExpBuffer(), Command::argc, Command::argv, Assert, buf, 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, PQExpBufferData::data, evaluateExpr(), evaluateSleep(), Command::expr, i, CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, initPQExpBuffer(), 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, PG_LOG_DEBUG, pg_log_debug, printfPQExpBuffer(), putVariableValue(), runShellCommand(), CState::sleep_until, termPQExpBuffer(), Command::type, unlikely, CState::use_file, and valueTruth().

Referenced by advanceConnectionState().

3312 {
3313  Command *command = sql_script[st->use_file].commands[st->command];
3314  int argc;
3315  char **argv;
3316 
3317  Assert(command != NULL && command->type == META_COMMAND);
3318 
3319  argc = command->argc;
3320  argv = command->argv;
3321 
3323  {
3325 
3326  initPQExpBuffer(&buf);
3327 
3328  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3329  for (int i = 1; i < argc; i++)
3330  appendPQExpBuffer(&buf, " %s", argv[i]);
3331 
3332  pg_log_debug("%s", buf.data);
3333 
3334  termPQExpBuffer(&buf);
3335  }
3336 
3337  if (command->meta == META_SLEEP)
3338  {
3339  int usec;
3340 
3341  /*
3342  * A \sleep doesn't execute anything, we just get the delay from the
3343  * argument, and enter the CSTATE_SLEEP state. (The per-command
3344  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3345  * delay has elapsed.)
3346  */
3347  if (!evaluateSleep(st, argc, argv, &usec))
3348  {
3349  commandFailed(st, "sleep", "execution of meta-command failed");
3350  return CSTATE_ABORTED;
3351  }
3352 
3354  st->sleep_until = INSTR_TIME_GET_MICROSEC(*now) + usec;
3355  return CSTATE_SLEEP;
3356  }
3357  else if (command->meta == META_SET)
3358  {
3359  PgBenchExpr *expr = command->expr;
3360  PgBenchValue result;
3361 
3362  if (!evaluateExpr(st, expr, &result))
3363  {
3364  commandFailed(st, argv[0], "evaluation of meta-command failed");
3365  return CSTATE_ABORTED;
3366  }
3367 
3368  if (!putVariableValue(st, argv[0], argv[1], &result))
3369  {
3370  commandFailed(st, "set", "assignment of meta-command failed");
3371  return CSTATE_ABORTED;
3372  }
3373  }
3374  else if (command->meta == META_IF)
3375  {
3376  /* backslash commands with an expression to evaluate */
3377  PgBenchExpr *expr = command->expr;
3378  PgBenchValue result;
3379  bool cond;
3380 
3381  if (!evaluateExpr(st, expr, &result))
3382  {
3383  commandFailed(st, argv[0], "evaluation of meta-command failed");
3384  return CSTATE_ABORTED;
3385  }
3386 
3387  cond = valueTruth(&result);
3389  }
3390  else if (command->meta == META_ELIF)
3391  {
3392  /* backslash commands with an expression to evaluate */
3393  PgBenchExpr *expr = command->expr;
3394  PgBenchValue result;
3395  bool cond;
3396 
3398  {
3399  /* elif after executed block, skip eval and wait for endif. */
3401  return CSTATE_END_COMMAND;
3402  }
3403 
3404  if (!evaluateExpr(st, expr, &result))
3405  {
3406  commandFailed(st, argv[0], "evaluation of meta-command failed");
3407  return CSTATE_ABORTED;
3408  }
3409 
3410  cond = valueTruth(&result);
3413  }
3414  else if (command->meta == META_ELSE)
3415  {
3416  switch (conditional_stack_peek(st->cstack))
3417  {
3418  case IFSTATE_TRUE:
3420  break;
3421  case IFSTATE_FALSE: /* inconsistent if active */
3422  case IFSTATE_IGNORED: /* inconsistent if active */
3423  case IFSTATE_NONE: /* else without if */
3424  case IFSTATE_ELSE_TRUE: /* else after else */
3425  case IFSTATE_ELSE_FALSE: /* else after else */
3426  default:
3427  /* dead code if conditional check is ok */
3428  Assert(false);
3429  }
3430  }
3431  else if (command->meta == META_ENDIF)
3432  {
3435  }
3436  else if (command->meta == META_SETSHELL)
3437  {
3438  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3439  {
3440  commandFailed(st, "setshell", "execution of meta-command failed");
3441  return CSTATE_ABORTED;
3442  }
3443  }
3444  else if (command->meta == META_SHELL)
3445  {
3446  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3447  {
3448  commandFailed(st, "shell", "execution of meta-command failed");
3449  return CSTATE_ABORTED;
3450  }
3451  }
3452 
3453  /*
3454  * executing the expression or shell command might have taken a
3455  * non-negligible amount of time, so reset 'now'
3456  */
3458 
3459  return CSTATE_END_COMMAND;
3460 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int type
Definition: pgbench.c:525
int id
Definition: pgbench.c:401
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
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:2615
PgBenchExpr * expr
Definition: pgbench.c:530
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
char * argv[MAX_ARGS]
Definition: pgbench.c:528
ConditionalStack cstack
Definition: pgbench.c:403
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2427
#define META_COMMAND
Definition: pgbench.c:467
#define pg_log_debug(...)
Definition: logging.h:91
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
static char * buf
Definition: pg_test_fsync.c:67
MetaCommand meta
Definition: pgbench.c:526
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:542
enum pg_log_level __pg_log_level
Definition: logging.c:16
int argc
Definition: pgbench.c:527
int command
Definition: pgbench.c:412
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2507
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
int64 sleep_until
Definition: pgbench.c:421
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:2844
#define INSTR_TIME_SET_CURRENT_LAZY(t)
Definition: instr_time.h:253
#define Assert(condition)
Definition: c.h:738
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:205
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1644
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:538
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:1477
#define unlikely(x)
Definition: c.h:206
int use_file
Definition: pgbench.c:411
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ executeStatement()

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

Definition at line 1142 of file pgbench.c.

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

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

1143 {
1144  PGresult *res;
1145 
1146  res = PQexec(con, sql);
1147  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1148  {
1149  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1150  pg_log_info("query was: %s", sql);
1151  exit(1);
1152  }
1153  PQclear(res);
1154 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6687
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
void PQclear(PGresult *res)
Definition: fe-exec.c:694
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define pg_log_info(...)
Definition: logging.h:87
#define pg_log_fatal(...)
Definition: logging.h:75

◆ findBuiltin()

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

Definition at line 4987 of file pgbench.c.

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

Referenced by main().

4988 {
4989  int i,
4990  found = 0,
4991  len = strlen(name);
4992  const BuiltinScript *result = NULL;
4993 
4994  for (i = 0; i < lengthof(builtin_script); i++)
4995  {
4996  if (strncmp(builtin_script[i].name, name, len) == 0)
4997  {
4998  result = &builtin_script[i];
4999  found++;
5000  }
5001  }
5002 
5003  /* ok, unambiguous result */
5004  if (found == 1)
5005  return result;
5006 
5007  /* error cases */
5008  if (found == 0)
5009  pg_log_fatal("no builtin script found for name \"%s\"", name);
5010  else /* found > 1 */
5011  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5012 
5014  exit(1);
5015 }
static void listAvailableScripts(void)
Definition: pgbench.c:4975
#define lengthof(array)
Definition: c.h:668
static const BuiltinScript builtin_script[]
Definition: pgbench.c:554
const char * name
Definition: encode.c:555
int i
#define pg_log_fatal(...)
Definition: logging.h:75

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6515 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6516 {
6517  if (st->con != NULL)
6518  {
6519  PQfinish(st->con);
6520  st->con = NULL;
6521  }
6522 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4185
PGconn * con
Definition: pgbench.c:400

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4466 of file pgbench.c.

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

Referenced by ParseScript().

4467 {
4468  termPQExpBuffer(&command->lines);
4469  if (command->first_line)
4470  pg_free(command->first_line);
4471  for (int i = 0; i < command->argc; i++)
4472  pg_free(command->argv[i]);
4473  if (command->varprefix)
4474  pg_free(command->varprefix);
4475 
4476  /*
4477  * It should also free expr recursively, but this is currently not needed
4478  * as only gset commands (which do not have an expression) are freed.
4479  */
4480  pg_free(command);
4481 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:528
PQExpBufferData lines
Definition: pgbench.c:523
int argc
Definition: pgbench.c:527
char * varprefix
Definition: pgbench.c:529
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:524

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6689 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6690 {
6691  pg_free(sa);
6692 }
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 870 of file pgbench.c.

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

Referenced by evalStandardFunc().

872 {
873  double cut,
874  uniform,
875  rand;
876 
877  /* abort if wrong parameter, but must really be checked beforehand */
878  Assert(parameter > 0.0);
879  cut = exp(-parameter);
880  /* erand in [0, 1), uniform in (0, 1] */
881  uniform = 1.0 - pg_erand48(random_state->xseed);
882 
883  /*
884  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
885  */
886  Assert((1.0 - cut) != 0.0);
887  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
888  /* return int64 random number within between min and max */
889  return min + (int64) ((max - min + 1) * rand);
890 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:738
unsigned short xseed[3]
Definition: pgbench.c:307

◆ getGaussianRand()

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

Definition at line 894 of file pgbench.c.

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

Referenced by evalStandardFunc().

896 {
897  double stdev;
898  double rand;
899 
900  /* abort if parameter is too low, but must really be checked beforehand */
901  Assert(parameter >= MIN_GAUSSIAN_PARAM);
902 
903  /*
904  * Get user specified random number from this loop, with -parameter <
905  * stdev <= parameter
906  *
907  * This loop is executed until the number is in the expected range.
908  *
909  * As the minimum parameter is 2.0, the probability of looping is low:
910  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
911  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
912  * the worst case. For a parameter value of 5.0, the looping probability
913  * is about e^{-5} * 2 / pi ~ 0.43%.
914  */
915  do
916  {
917  /*
918  * pg_erand48 generates [0,1), but for the basic version of the
919  * Box-Muller transform the two uniformly distributed random numbers
920  * are expected in (0, 1] (see
921  * https://en.wikipedia.org/wiki/Box-Muller_transform)
922  */
923  double rand1 = 1.0 - pg_erand48(random_state->xseed);
924  double rand2 = 1.0 - pg_erand48(random_state->xseed);
925 
926  /* Box-Muller basic form transform */
927  double var_sqrt = sqrt(-2.0 * log(rand1));
928 
929  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
930 
931  /*
932  * we may try with cos, but there may be a bias induced if the
933  * previous value fails the test. To be on the safe side, let us try
934  * over.
935  */
936  }
937  while (stdev < -parameter || stdev >= parameter);
938 
939  /* stdev is in [-parameter, parameter), normalization to [0,1) */
940  rand = (stdev + parameter) / (parameter * 2.0);
941 
942  /* return int64 random number within between min and max */
943  return min + (int64) ((max - min + 1) * rand);
944 }
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:140
#define M_PI
Definition: pgbench.c:70
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:738
unsigned short xseed[3]
Definition: pgbench.c:307

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1020 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1021 {
1022  int64 result;
1023  int i;
1024 
1025  result = FNV_OFFSET_BASIS ^ seed;
1026  for (i = 0; i < 8; ++i)
1027  {
1028  int32 octet = val & 0xff;
1029 
1030  val = val >> 8;
1031  result = result ^ octet;
1032  result = result * FNV_PRIME;
1033  }
1034 
1035  return result;
1036 }
#define FNV_PRIME
Definition: pgbench.c:78
#define FNV_OFFSET_BASIS
Definition: pgbench.c:79
signed int int32
Definition: c.h:355
int i
long val
Definition: informix.c:664

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1045 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1046 {
1047  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1048  uint64 k = (uint64) val;
1049 
1050  k *= MM2_MUL;
1051  k ^= k >> MM2_ROT;
1052  k *= MM2_MUL;
1053 
1054  result ^= k;
1055  result *= MM2_MUL;
1056 
1057  result ^= result >> MM2_ROT;
1058  result *= MM2_MUL;
1059  result ^= result >> MM2_ROT;
1060 
1061  return (int64) result;
1062 }
#define MM2_MUL_TIMES_8
Definition: pgbench.c:81
#define MM2_ROT
Definition: pgbench.c:82
long val
Definition: informix.c:664
#define MM2_MUL
Definition: pgbench.c:80

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2471 of file pgbench.c.

References META_ASET, 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().

2472 {
2473  MetaCommand mc;
2474 
2475  if (cmd == NULL)
2476  mc = META_NONE;
2477  else if (pg_strcasecmp(cmd, "set") == 0)
2478  mc = META_SET;
2479  else if (pg_strcasecmp(cmd, "setshell") == 0)
2480  mc = META_SETSHELL;
2481  else if (pg_strcasecmp(cmd, "shell") == 0)
2482  mc = META_SHELL;
2483  else if (pg_strcasecmp(cmd, "sleep") == 0)
2484  mc = META_SLEEP;
2485  else if (pg_strcasecmp(cmd, "if") == 0)
2486  mc = META_IF;
2487  else if (pg_strcasecmp(cmd, "elif") == 0)
2488  mc = META_ELIF;
2489  else if (pg_strcasecmp(cmd, "else") == 0)
2490  mc = META_ELSE;
2491  else if (pg_strcasecmp(cmd, "endif") == 0)
2492  mc = META_ENDIF;
2493  else if (pg_strcasecmp(cmd, "gset") == 0)
2494  mc = META_GSET;
2495  else if (pg_strcasecmp(cmd, "aset") == 0)
2496  mc = META_ASET;
2497  else
2498  mc = META_NONE;
2499  return mc;
2500 }
MetaCommand
Definition: pgbench.c:475
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 954 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

955 {
956  /*
957  * Use inverse transform sampling to generate a value > 0, such that the
958  * expected (i.e. average) value is the given argument.
959  */
960  double uniform;
961 
962  /* erand in [0, 1), uniform in (0, 1] */
963  uniform = 1.0 - pg_erand48(random_state->xseed);
964 
965  return (int64) (-log(uniform) * center + 0.5);
966 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:307

◆ getQueryParams()

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

Definition at line 1593 of file pgbench.c.

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

Referenced by sendCommand().

1594 {
1595  int i;
1596 
1597  for (i = 0; i < command->argc - 1; i++)
1598  params[i] = getVariable(st, command->argv[i + 1]);
1599 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1276
char * argv[MAX_ARGS]
Definition: pgbench.c:528
int argc
Definition: pgbench.c:527
int i

◆ getrand()

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

Definition at line 850 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

851 {
852  /*
853  * Odd coding is so that min and max have approximately the same chance of
854  * being selected as do numbers between them.
855  *
856  * pg_erand48() is thread-safe and concurrent, which is why we use it
857  * rather than random(), which in glibc is non-reentrant, and therefore
858  * protected by a mutex, and therefore a bottleneck on machines with many
859  * CPUs.
860  */
861  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
862 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:307

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4195 of file pgbench.c.

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

Referenced by main().

4196 {
4197  PGresult *res;
4198 
4199  /*
4200  * get the scaling factor that should be same as count(*) from
4201  * pgbench_branches if this is not a custom query
4202  */
4203  res = PQexec(con, "select count(*) from pgbench_branches");
4204  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4205  {
4206  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4207 
4208  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4209 
4210  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4211  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4212  PQdb(con));
4213 
4214  exit(1);
4215  }
4216  scale = atoi(PQgetvalue(res, 0, 0));
4217  if (scale < 0)
4218  {
4219  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4220  PQgetvalue(res, 0, 0));
4221  exit(1);
4222  }
4223  PQclear(res);
4224 
4225  /* warn if we override user-given -s switch */
4226  if (scale_given)
4227  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4228  scale);
4229 
4230  /*
4231  * Get the partition information for the first "pgbench_accounts" table
4232  * found in search_path.
4233  *
4234  * The result is empty if no "pgbench_accounts" is found.
4235  *
4236  * Otherwise, it always returns one row even if the table is not
4237  * partitioned (in which case the partition strategy is NULL).
4238  *
4239  * The number of partitions can be 0 even for partitioned tables, if no
4240  * partition is attached.
4241  *
4242  * We assume no partitioning on any failure, so as to avoid failing on an
4243  * old version without "pg_partitioned_table".
4244  */
4245  res = PQexec(con,
4246  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4247  "from pg_catalog.pg_class as c "
4248  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4249  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4250  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4251  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4252  "where c.relname = 'pgbench_accounts' and o.n is not null "
4253  "group by 1, 2 "
4254  "order by 1 asc "
4255  "limit 1");
4256 
4257  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4258  {
4259  /* probably an older version, coldly assume no partitioning */
4261  partitions = 0;
4262  }
4263  else if (PQntuples(res) == 0)
4264  {
4265  /*
4266  * This case is unlikely as pgbench already found "pgbench_branches"
4267  * above to compute the scale.
4268  */
4269  pg_log_fatal("no pgbench_accounts table found in search_path");
4270  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4271  exit(1);
4272  }
4273  else /* PQntupes(res) == 1 */
4274  {
4275  /* normal case, extract partition information */
4276  if (PQgetisnull(res, 0, 1))
4278  else
4279  {
4280  char *ps = PQgetvalue(res, 0, 1);
4281 
4282  /* column must be there */
4283  Assert(ps != NULL);
4284 
4285  if (strcmp(ps, "r") == 0)
4287  else if (strcmp(ps, "h") == 0)
4289  else
4290  {
4291  /* possibly a newer version with new partition method */
4292  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4293  exit(1);
4294  }
4295  }
4296 
4297  partitions = atoi(PQgetvalue(res, 0, 2));
4298  }
4299 
4300  PQclear(res);
4301 }
static int partitions
Definition: pgbench.c:195
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6687
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:73
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3163
static partition_method_t partition_method
Definition: pgbench.c:205
int scale
Definition: pgbench.c:153
int PQntuples(const PGresult *res)
Definition: fe-exec.c:2769
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6537
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:2754
#define Assert(condition)
Definition: c.h:738
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define pg_log_warning(...)
Definition: pgfnames.c:24
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3188
#define pg_log_info(...)
Definition: logging.h:87
#define pg_log_fatal(...)
Definition: logging.h:75

◆ getVariable()

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

Definition at line 1276 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().

1277 {
1278  Variable *var;
1279  char stringform[64];
1280 
1281  var = lookupVariable(st, name);
1282  if (var == NULL)
1283  return NULL; /* not found */
1284 
1285  if (var->svalue)
1286  return var->svalue; /* we have it in string form */
1287 
1288  /* We need to produce a string equivalent of the value */
1289  Assert(var->value.type != PGBT_NO_VALUE);
1290  if (var->value.type == PGBT_NULL)
1291  snprintf(stringform, sizeof(stringform), "NULL");
1292  else if (var->value.type == PGBT_BOOLEAN)
1293  snprintf(stringform, sizeof(stringform),
1294  "%s", var->value.u.bval ? "true" : "false");
1295  else if (var->value.type == PGBT_INT)
1296  snprintf(stringform, sizeof(stringform),
1297  INT64_FORMAT, var->value.u.ival);
1298  else if (var->value.type == PGBT_DOUBLE)
1299  snprintf(stringform, sizeof(stringform),
1300  "%.*g", DBL_DIG, var->value.u.dval);
1301  else /* internal error, unexpected type */
1302  Assert(0);
1303  var->svalue = pg_strdup(stringform);
1304  return var->svalue;
1305 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1249
union PgBenchValue::@38 u
char * svalue
Definition: pgbench.c:266
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
PgBenchValue value
Definition: pgbench.c:267
double dval
Definition: pgbench.h:50
#define Assert(condition)
Definition: c.h:738
#define INT64_FORMAT
Definition: c.h:409
const char * name
Definition: encode.c:555
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:193

◆ getZipfianRand()

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

Definition at line 1006 of file pgbench.c.

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

Referenced by evalStandardFunc().

1007 {
1008  int64 n = max - min + 1;
1009 
1010  /* abort if parameter is invalid */
1012 
1013  return min - 1 + computeIterativeZipfian(random_state, n, s);
1014 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:143
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:142
#define Assert(condition)
Definition: c.h:738
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:976

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6531 of file pgbench.c.

Referenced by setalarm().

6532 {
6533  timer_exceeded = true;
6534 }
volatile bool timer_exceeded
Definition: pgbench.c:251

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4054 of file pgbench.c.

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

Referenced by runInitSteps().

4055 {
4056  static const char *const DDLKEYs[] = {
4057  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4058  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4059  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4060  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4061  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4062  };
4063  int i;
4064 
4065  fprintf(stderr, "creating foreign keys...\n");
4066  for (i = 0; i < lengthof(DDLKEYs); i++)
4067  {
4068  executeStatement(con, DDLKEYs[i]);
4069  }
4070 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4019 of file pgbench.c.

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

Referenced by runInitSteps().

4020 {
4021  static const char *const DDLINDEXes[] = {
4022  "alter table pgbench_branches add primary key (bid)",
4023  "alter table pgbench_tellers add primary key (tid)",
4024  "alter table pgbench_accounts add primary key (aid)"
4025  };
4026  int i;
4027 
4028  fprintf(stderr, "creating primary keys...\n");
4029  for (i = 0; i < lengthof(DDLINDEXes); i++)
4030  {
4031  char buffer[256];
4032 
4033  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
4034 
4035  if (index_tablespace != NULL)
4036  {
4037  char *escape_tablespace;
4038 
4039  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4040  strlen(index_tablespace));
4041  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
4042  " using index tablespace %s", escape_tablespace);
4043  PQfreemem(escape_tablespace);
4044  }
4045 
4046  executeStatement(con, buffer);
4047  }
4048 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3570
char * index_tablespace
Definition: pgbench.c:189
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
int i
#define snprintf
Definition: port.h:193
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 3700 of file pgbench.c.

References append_fillfactor(), createPartitions(), executeStatement(), fprintf, i, lengthof, PART_NONE, partition_method, PQescapeIdentifier(), PQfreemem(), SCALE_32BIT_THRESHOLD, and snprintf.

Referenced by runInitSteps().

3701 {
3702  /*
3703  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
3704  * fields in these table declarations were intended to comply with that.
3705  * The pgbench_accounts table complies with that because the "filler"
3706  * column is set to blank-padded empty string. But for all other tables
3707  * the columns default to NULL and so don't actually take any space. We
3708  * could fix that by giving them non-null default values. However, that
3709  * would completely break comparability of pgbench results with prior
3710  * versions. Since pgbench has never pretended to be fully TPC-B compliant
3711  * anyway, we stick with the historical behavior.
3712  */
3713  struct ddlinfo
3714  {
3715  const char *table; /* table name */
3716  const char *smcols; /* column decls if accountIDs are 32 bits */
3717  const char *bigcols; /* column decls if accountIDs are 64 bits */
3718  int declare_fillfactor;
3719  };
3720  static const struct ddlinfo DDLs[] = {
3721  {
3722  "pgbench_history",
3723  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
3724  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
3725  0
3726  },
3727  {
3728  "pgbench_tellers",
3729  "tid int not null,bid int,tbalance int,filler char(84)",
3730  "tid int not null,bid int,tbalance int,filler char(84)",
3731  1
3732  },
3733  {
3734  "pgbench_accounts",
3735  "aid int not null,bid int,abalance int,filler char(84)",
3736  "aid bigint not null,bid int,abalance int,filler char(84)",
3737  1
3738  },
3739  {
3740  "pgbench_branches",
3741  "bid int not null,bbalance int,filler char(88)",
3742  "bid int not null,bbalance int,filler char(88)",
3743  1
3744  }
3745  };
3746  int i;
3747 
3748  fprintf(stderr, "creating tables...\n");
3749 
3750  for (i = 0; i < lengthof(DDLs); i++)
3751  {
3752  char opts[256];
3753  char buffer[256];
3754  const struct ddlinfo *ddl = &DDLs[i];
3755  const char *cols;
3756 
3757  /* Construct new create table statement. */
3758  opts[0] = '\0';
3759 
3760  /* Partition pgbench_accounts table */
3761  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
3762  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3763  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
3764  else if (ddl->declare_fillfactor)
3765  /* fillfactor is only expected on actual tables */
3766  append_fillfactor(opts, sizeof(opts));
3767 
3768  if (tablespace != NULL)
3769  {
3770  char *escape_tablespace;
3771 
3772  escape_tablespace = PQescapeIdentifier(con, tablespace,
3773  strlen(tablespace));
3774  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3775  " tablespace %s", escape_tablespace);
3776  PQfreemem(escape_tablespace);
3777  }
3778 
3779  cols = (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols;
3780 
3781  snprintf(buffer, sizeof(buffer), "create%s table %s(%s)%s",
3782  unlogged_tables ? " unlogged" : "",
3783  ddl->table, cols, opts);
3784 
3785  executeStatement(con, buffer);
3786  }
3787 
3788  if (partition_method != PART_NONE)
3789  createPartitions(con);
3790 }
static partition_method_t partition_method
Definition: pgbench.c:205
int scale
Definition: pgbench.c:153
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:227
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3570
static void append_fillfactor(char *opts, int len)
Definition: pgbench.c:3798
char * tablespace
Definition: pgbench.c:188
static const char * PARTITION_METHOD[]
Definition: pgbench.c:206
bool unlogged_tables
Definition: pgbench.c:164
int i
static void createPartitions(PGconn *con)
Definition: pgbench.c:3632
#define snprintf
Definition: port.h:193
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3610 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3611 {
3612  fprintf(stderr, "dropping old tables...\n");
3613 
3614  /*
3615  * We drop all the tables in one command, so that whether there are
3616  * foreign key dependencies or not doesn't matter.
3617  */
3618  executeStatement(con, "drop table if exists "
3619  "pgbench_accounts, "
3620  "pgbench_branches, "
3621  "pgbench_history, "
3622  "pgbench_tellers");
3623 }
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 3821 of file pgbench.c.

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

Referenced by runInitSteps().

3822 {
3823  char sql[256];
3824  PGresult *res;
3825  int i;
3826  int64 k;
3827 
3828  /* used to track elapsed time and estimate of the remaining time */
3829  instr_time start,
3830  diff;
3831  double elapsed_sec,
3832  remaining_sec;
3833  int log_interval = 1;
3834 
3835  /* Stay on the same line if reporting to a terminal */
3836  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
3837 
3838  fprintf(stderr, "generating data (client-side)...\n");
3839 
3840  /*
3841  * we do all of this in one transaction to enable the backend's
3842  * data-loading optimizations
3843  */
3844  executeStatement(con, "begin");
3845 
3846  /* truncate away any old data */
3847  initTruncateTables(con);
3848 
3849  /*
3850  * fill branches, tellers, accounts in that order in case foreign keys
3851  * already exist
3852  */
3853  for (i = 0; i < nbranches * scale; i++)
3854  {
3855  /* "filler" column defaults to NULL */
3856  snprintf(sql, sizeof(sql),
3857  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
3858  i + 1);
3859  executeStatement(con, sql);
3860  }
3861 
3862  for (i = 0; i < ntellers * scale; i++)
3863  {
3864  /* "filler" column defaults to NULL */
3865  snprintf(sql, sizeof(sql),
3866  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
3867  i + 1, i / ntellers + 1);
3868  executeStatement(con, sql);
3869  }
3870 
3871  /*
3872  * accounts is big enough to be worth using COPY and tracking runtime
3873  */
3874  res = PQexec(con, "copy pgbench_accounts from stdin");
3875  if (PQresultStatus(res) != PGRES_COPY_IN)
3876  {
3877  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
3878  exit(1);
3879  }
3880  PQclear(res);
3881 
3882  INSTR_TIME_SET_CURRENT(start);
3883 
3884  for (k = 0; k < (int64) naccounts * scale; k++)
3885  {
3886  int64 j = k + 1;
3887 
3888  /* "filler" column defaults to blank padded empty string */
3889  snprintf(sql, sizeof(sql),
3890  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
3891  j, k / naccounts + 1, 0);
3892  if (PQputline(con, sql))
3893  {
3894  pg_log_fatal("PQputline failed");
3895  exit(1);
3896  }
3897 
3898  if (CancelRequested)
3899  break;
3900 
3901  /*
3902  * If we want to stick with the original logging, print a message each
3903  * 100k inserted rows.
3904  */
3905  if ((!use_quiet) && (j % 100000 == 0))
3906  {
3907  INSTR_TIME_SET_CURRENT(diff);
3908  INSTR_TIME_SUBTRACT(diff, start);
3909 
3910  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3911  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3912 
3913  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3914  j, (int64) naccounts * scale,
3915  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
3916  elapsed_sec, remaining_sec, eol);
3917  }
3918  /* let's not call the timing for each row, but only each 100 rows */
3919  else if (use_quiet && (j % 100 == 0))
3920  {
3921  INSTR_TIME_SET_CURRENT(diff);
3922  INSTR_TIME_SUBTRACT(diff, start);
3923 
3924  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3925  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3926 
3927  /* have we reached the next interval (or end)? */
3928  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
3929  {
3930  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3931  j, (int64) naccounts * scale,
3932  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
3933 
3934  /* skip to the next interval */
3935  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
3936  }
3937  }
3938  }
3939 
3940  if (eol != '\n')
3941  fputc('\n', stderr); /* Need to move to next line */
3942 
3943  if (PQputline(con, "\\.\n"))
3944  {
3945  pg_log_fatal("very last PQputline failed");
3946  exit(1);
3947  }
3948  if (PQendcopy(con))
3949  {
3950  pg_log_fatal("PQendcopy failed");
3951  exit(1);
3952  }
3953 
3954  executeStatement(con, "commit");
3955 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6687
struct timeval instr_time
Definition: instr_time.h:150
int scale
Definition: pgbench.c:153
#define INSTR_TIME_GET_DOUBLE(t)
Definition: instr_time.h:199
#define LOG_STEP_SECONDS
Definition: pgbench.c:137
#define fprintf
Definition: port.h:197
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:2692
bool use_quiet
Definition: pgbench.c:230
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2585
#define nbranches
Definition: pgbench.c:215
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define ntellers
Definition: pgbench.c:217
#define naccounts
Definition: pgbench.c:218
void PQclear(PGresult *res)
Definition: fe-exec.c:694
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2618
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3808
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define INT64_FORMAT
Definition: c.h:409
volatile sig_atomic_t CancelRequested
Definition: cancel.c:52
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:1939
#define snprintf
Definition: port.h:193
#define pg_log_fatal(...)
Definition: logging.h:75

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 3965 of file pgbench.c.

References executeStatement(), fprintf, initTruncateTables(), INT64_FORMAT, naccounts, nbranches, ntellers, and snprintf.

Referenced by runInitSteps().

3966 {
3967  char sql[256];
3968 
3969  fprintf(stderr, "generating data (server-side)...\n");
3970 
3971  /*
3972  * we do all of this in one transaction to enable the backend's
3973  * data-loading optimizations
3974  */
3975  executeStatement(con, "begin");
3976 
3977  /* truncate away any old data */
3978  initTruncateTables(con);
3979 
3980  snprintf(sql, sizeof(sql),
3981  "insert into pgbench_branches(bid,bbalance) "
3982  "select bid, 0 "
3983  "from generate_series(1, %d) as bid", nbranches * scale);
3984  executeStatement(con, sql);
3985 
3986  snprintf(sql, sizeof(sql),
3987  "insert into pgbench_tellers(tid,bid,tbalance) "
3988  "select tid, (tid - 1) / %d + 1, 0 "
3989  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
3990  executeStatement(con, sql);
3991 
3992  snprintf(sql, sizeof(sql),
3993  "insert into pgbench_accounts(aid,bid,abalance,filler) "
3994  "select aid, (aid - 1) / %d + 1, 0, '' "
3995  "from generate_series(1, " INT64_FORMAT ") as aid",
3996  naccounts, (int64) naccounts * scale);
3997  executeStatement(con, sql);
3998 
3999  executeStatement(con, "commit");
4000 }
int scale
Definition: pgbench.c:153
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define nbranches
Definition: pgbench.c:215
#define ntellers
Definition: pgbench.c:217
#define naccounts
Definition: pgbench.c:218
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3808
#define INT64_FORMAT
Definition: c.h:409
#define snprintf
Definition: port.h:193

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 831 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

832 {
833  random_state->xseed[0] = (unsigned short)
835  random_state->xseed[1] = (unsigned short)
837  random_state->xseed[2] = (unsigned short)
839 }
static RandomState base_random_sequence
Definition: pgbench.c:311
unsigned short xseed[3]
Definition: pgbench.c:307
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:112

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1068 of file pgbench.c.

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

1069 {
1070  memset(ss, 0, sizeof(SimpleStats));
1071 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 1108 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().

1109 {
1110  sd->start_time = start_time;
1111  sd->cnt = 0;
1112  sd->skipped = 0;
1113  initSimpleStats(&sd->latency);
1114  initSimpleStats(&sd->lag);
1115 }
time_t start_time
Definition: pgbench.c:294
SimpleStats lag
Definition: pgbench.c:299
SimpleStats latency
Definition: pgbench.c:298
static time_t start_time
Definition: pg_ctl.c:99
int64 cnt
Definition: pgbench.c:295
int64 skipped
Definition: pgbench.c:296
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1068

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 3808 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

3809 {
3810  executeStatement(con, "truncate table "
3811  "pgbench_accounts, "
3812  "pgbench_branches, "
3813  "pgbench_history, "
3814  "pgbench_tellers");
3815 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4006 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

4007 {
4008  fprintf(stderr, "vacuuming...\n");
4009  executeStatement(con, "vacuum analyze pgbench_branches");
4010  executeStatement(con, "vacuum analyze pgbench_tellers");
4011  executeStatement(con, "vacuum analyze pgbench_accounts");
4012  executeStatement(con, "vacuum analyze pgbench_history");
4013 }
#define fprintf
Definition: port.h:197
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 694 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

695 {
696  const char *ptr = str;
697 
698  /* skip leading spaces; cast is consistent with strtoint64 */
699  while (*ptr && isspace((unsigned char) *ptr))
700  ptr++;
701 
702  /* skip sign */
703  if (*ptr == '+' || *ptr == '-')
704  ptr++;
705 
706  /* at least one digit */
707  if (*ptr && !isdigit((unsigned char) *ptr))
708  return false;
709 
710  /* eat all digits */
711  while (*ptr && isdigit((unsigned char) *ptr))
712  ptr++;
713 
714  /* must have reached end of string */
715  return *ptr == '\0';
716 }

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1745 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1746 {
1747  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1748 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4975 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4976 {
4977  int i;
4978 
4979  fprintf(stderr, "Available builtin scripts:\n");
4980  for (i = 0; i < lengthof(builtin_script); i++)
4981  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4982  fprintf(stderr, "\n");
4983 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:197
static const BuiltinScript builtin_script[]
Definition: pgbench.c:554
const char * name
Definition: encode.c:555
int i

◆ lookupCreateVariable()

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

Definition at line 1409 of file pgbench.c.

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

Referenced by putVariable(), and putVariableValue().

1410 {
1411  Variable *var;
1412 
1413  var = lookupVariable(st, name);
1414  if (var == NULL)
1415  {
1416  Variable *newvars;
1417 
1418  /*
1419  * Check for the name only when declaring a new variable to avoid
1420  * overhead.
1421  */
1422  if (!valid_variable_name(name))
1423  {
1424  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1425  return NULL;
1426  }
1427 
1428  /* Create variable at the end of the array */
1429  if (st->variables)
1430  newvars = (Variable *) pg_realloc(st->variables,
1431  (st->nvariables + 1) * sizeof(Variable));
1432  else
1433  newvars = (Variable *) pg_malloc(sizeof(Variable));
1434 
1435  st->variables = newvars;
1436 
1437  var = &newvars[st->nvariables];
1438 
1439  var->name = pg_strdup(name);
1440  var->svalue = NULL;
1441  /* caller is expected to initialize remaining fields */
1442 
1443  st->nvariables++;
1444  /* we don't re-sort the array till we have to */
1445  st->vars_sorted = false;
1446  }
1447 
1448  return var;
1449 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1249
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
char * name
Definition: pgbench.c:265
#define pg_log_error(...)
Definition: logging.h:79
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1382
Variable * variables
Definition: pgbench.c:415
bool vars_sorted
Definition: pgbench.c:417
char * svalue
Definition: pgbench.c:266
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:555
int nvariables
Definition: pgbench.c:416

◆ lookupVariable()

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

Definition at line 1249 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().

1250 {
1251  Variable key;
1252 
1253  /* On some versions of Solaris, bsearch of zero items dumps core */
1254  if (st->nvariables <= 0)
1255  return NULL;
1256 
1257  /* Sort if we have to */
1258  if (!st->vars_sorted)
1259  {
1260  qsort((void *) st->variables, st->nvariables, sizeof(Variable),
1262  st->vars_sorted = true;
1263  }
1264 
1265  /* Now we can search */
1266  key.name = name;
1267  return (Variable *) bsearch((void *) &key,
1268  (void *) st->variables,
1269  st->nvariables,
1270  sizeof(Variable),
1272 }
char * name
Definition: pgbench.c:265
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1241
Variable * variables
Definition: pgbench.c:415
bool vars_sorted
Definition: pgbench.c:417
const char * name
Definition: encode.c:555
int nvariables
Definition: pgbench.c:416
#define qsort(a, b, c, d)
Definition: port.h:479

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5381 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(), findBuiltin(), fprintf, get_progname(), getopt_long(), GetTableInfo(), 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(), PART_HASH, PART_NONE, PART_RANGE, pg_free(), pg_jrand48(), PG_LOG_DEBUG, pg_log_debug, pg_log_fatal, pg_log_info, pg_logging_init(), pg_logging_set_level(), pg_malloc(), pg_malloc0(), pg_realloc(), pg_strcasecmp(), pg_strdup(), PGBT_NO_VALUE, postprocess_sql_command(), PQerrorMessage(), PQfinish(), PQstatus(), 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, 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.

5382 {
5383  static struct option long_options[] = {
5384  /* systematic long/short named options */
5385  {"builtin", required_argument, NULL, 'b'},
5386  {"client", required_argument, NULL, 'c'},
5387  {"connect", no_argument, NULL, 'C'},
5388  {"debug", no_argument, NULL, 'd'},
5389  {"define", required_argument, NULL, 'D'},
5390  {"file", required_argument, NULL, 'f'},
5391  {"fillfactor", required_argument, NULL, 'F'},
5392  {"host", required_argument, NULL, 'h'},
5393  {"initialize", no_argument, NULL, 'i'},
5394  {"init-steps", required_argument, NULL, 'I'},
5395  {"jobs", required_argument, NULL, 'j'},
5396  {"log", no_argument, NULL, 'l'},
5397  {"latency-limit", required_argument, NULL, 'L'},
5398  {"no-vacuum", no_argument, NULL, 'n'},
5399  {"port", required_argument, NULL, 'p'},
5400  {"progress", required_argument, NULL, 'P'},
5401  {"protocol", required_argument, NULL, 'M'},
5402  {"quiet", no_argument, NULL, 'q'},
5403  {"report-latencies", no_argument, NULL, 'r'},
5404  {"rate", required_argument, NULL, 'R'},
5405  {"scale", required_argument, NULL, 's'},
5406  {"select-only", no_argument, NULL, 'S'},
5407  {"skip-some-updates", no_argument, NULL, 'N'},
5408  {"time", required_argument, NULL, 'T'},
5409  {"transactions", required_argument, NULL, 't'},
5410  {"username", required_argument, NULL, 'U'},
5411  {"vacuum-all", no_argument, NULL, 'v'},
5412  /* long-named only options */
5413  {"unlogged-tables", no_argument, NULL, 1},
5414  {"tablespace", required_argument, NULL, 2},
5415  {"index-tablespace", required_argument, NULL, 3},
5416  {"sampling-rate", required_argument, NULL, 4},
5417  {"aggregate-interval", required_argument, NULL, 5},
5418  {"progress-timestamp", no_argument, NULL, 6},
5419  {"log-prefix", required_argument, NULL, 7},
5420  {"foreign-keys", no_argument, NULL, 8},
5421  {"random-seed", required_argument, NULL, 9},
5422  {"show-script", required_argument, NULL, 10},
5423  {"partitions", required_argument, NULL, 11},
5424  {"partition-method", required_argument, NULL, 12},
5425  {NULL, 0, NULL, 0}
5426  };
5427 
5428  int c;
5429  bool is_init_mode = false; /* initialize mode? */
5430  char *initialize_steps = NULL;
5431  bool foreign_keys = false;
5432  bool is_no_vacuum = false;
5433  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5434  int optindex;
5435  bool scale_given = false;
5436 
5437  bool benchmarking_option_set = false;
5438  bool initialization_option_set = false;
5439  bool internal_script_used = false;
5440 
5441  CState *state; /* status of clients */
5442  TState *threads; /* array of thread */
5443 
5444  instr_time start_time; /* start up time */
5445  instr_time total_time;
5446  instr_time conn_total_time;
5447  int64 latency_late = 0;
5448  StatsData stats;
5449  int weight;
5450 
5451  int i;
5452  int nclients_dealt;
5453 
5454 #ifdef HAVE_GETRLIMIT
5455  struct rlimit rlim;
5456 #endif
5457 
5458  PGconn *con;
5459  char *env;
5460 
5461  int exit_code = 0;
5462 
5463  pg_logging_init(argv[0]);
5464  progname = get_progname(argv[0]);
5465 
5466  if (argc > 1)
5467  {
5468  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5469  {
5470  usage();
5471  exit(0);
5472  }
5473  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5474  {
5475  puts("pgbench (PostgreSQL) " PG_VERSION);
5476  exit(0);
5477  }
5478  }
5479 
5480  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
5481  pghost = env;
5482  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
5483  pgport = env;
5484  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
5485  login = env;
5486 
5487  state = (CState *) pg_malloc0(sizeof(CState));
5488 
5489  /* set random seed early, because it may be used while parsing scripts. */
5490  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5491  {
5492  pg_log_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
5493  exit(1);
5494  }
5495 
5496  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)
5497  {
5498  char *script;
5499 
5500  switch (c)
5501  {
5502  case 'i':
5503  is_init_mode = true;
5504  break;
5505  case 'I':
5506  if (initialize_steps)
5507  pg_free(initialize_steps);
5508  initialize_steps = pg_strdup(optarg);
5509  checkInitSteps(initialize_steps);
5510  initialization_option_set = true;
5511  break;
5512  case 'h':
5513  pghost = pg_strdup(optarg);
5514  break;
5515  case 'n':
5516  is_no_vacuum = true;
5517  break;
5518  case 'v':
5519  benchmarking_option_set = true;
5520  do_vacuum_accounts = true;
5521  break;
5522  case 'p':
5523  pgport = pg_strdup(optarg);
5524  break;
5525  case 'd':
5527  break;
5528  case 'c':
5529  benchmarking_option_set = true;
5530  nclients = atoi(optarg);
5531  if (nclients <= 0)
5532  {
5533  pg_log_fatal("invalid number of clients: \"%s\"", optarg);
5534  exit(1);
5535  }
5536 #ifdef HAVE_GETRLIMIT
5537 #ifdef RLIMIT_NOFILE /* most platforms use RLIMIT_NOFILE */
5538  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
5539 #else /* but BSD doesn't ... */
5540  if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
5541 #endif /* RLIMIT_NOFILE */
5542  {
5543  pg_log_fatal("getrlimit failed: %m");
5544  exit(1);
5545  }
5546  if (rlim.rlim_cur < nclients + 3)
5547  {
5548  pg_log_fatal("need at least %d open files, but system limit is %ld",
5549  nclients + 3, (long) rlim.rlim_cur);
5550  pg_log_info("Reduce number of clients, or use limit/ulimit to increase the system limit.");
5551  exit(1);
5552  }
5553 #endif /* HAVE_GETRLIMIT */
5554  break;
5555  case 'j': /* jobs */
5556  benchmarking_option_set = true;
5557  nthreads = atoi(optarg);
5558  if (nthreads <= 0)
5559  {
5560  pg_log_fatal("invalid number of threads: \"%s\"", optarg);
5561  exit(1);
5562  }
5563 #ifndef ENABLE_THREAD_SAFETY
5564  if (nthreads != 1)
5565  {
5566  pg_log_fatal("threads are not supported on this platform; use -j1");
5567  exit(1);
5568  }
5569 #endif /* !ENABLE_THREAD_SAFETY */
5570  break;
5571  case 'C':
5572  benchmarking_option_set = true;
5573  is_connect = true;
5574  break;