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_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, 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 1859 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2602 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_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_IF, /* \if */
484  META_ELIF, /* \elif */
485  META_ELSE, /* \else */
486  META_ENDIF /* \endif */
487 } 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 489 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1118 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1119 {
1120  stats->cnt++;
1121 
1122  if (skipped)
1123  {
1124  /* no latency to record on skipped transactions */
1125  stats->skipped++;
1126  }
1127  else
1128  {
1129  addToSimpleStats(&stats->latency, lat);
1130 
1131  /* and possibly the same for schedule lag */
1132  if (throttle_delay)
1133  addToSimpleStats(&stats->lag, lag);
1134  }
1135 }
SimpleStats lag
Definition: pgbench.c:299
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1074
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 6676 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6677 {
6678  if (fd < 0 || fd >= FD_SETSIZE)
6679  {
6680  /*
6681  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6682  * complicating the API to make it less grotty.
6683  */
6684  pg_log_fatal("too many client connections for select()");
6685  exit(1);
6686  }
6687  FD_SET(fd, &sa->fds);
6688  if (fd > sa->maxfd)
6689  sa->maxfd = fd;
6690 }
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 5040 of file pgbench.c.

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

Referenced by ParseScript().

5041 {
5042  if (script.commands == NULL || script.commands[0] == NULL)
5043  {
5044  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5045  exit(1);
5046  }
5047 
5048  if (num_scripts >= MAX_SCRIPTS)
5049  {
5050  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5051  exit(1);
5052  }
5053 
5054  CheckConditional(script);
5055 
5056  sql_script[num_scripts] = script;
5057  num_scripts++;
5058 }
static int num_scripts
Definition: pgbench.c:540
#define MAX_SCRIPTS
Definition: pgbench.c:270
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4693
const char * desc
Definition: pgbench.c:533
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
Command ** commands
Definition: pgbench.c:535
#define pg_log_fatal(...)
Definition: logging.h:75

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1074 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1075 {
1076  if (ss->count == 0 || val < ss->min)
1077  ss->min = val;
1078  if (ss->count == 0 || val > ss->max)
1079  ss->max = val;
1080  ss->count++;
1081  ss->sum += val;
1082  ss->sum2 += val * val;
1083 }
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 2858 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().

2859 {
2860  instr_time now;
2861 
2862  /*
2863  * gettimeofday() isn't free, so we get the current timestamp lazily the
2864  * first time it's needed, and reuse the same value throughout this
2865  * function after that. This also ensures that e.g. the calculated
2866  * latency reported in the log file and in the totals are the same. Zero
2867  * means "not set yet". Reset "now" when we execute shell commands or
2868  * expressions, which might take a non-negligible amount of time, though.
2869  */
2870  INSTR_TIME_SET_ZERO(now);
2871 
2872  /*
2873  * Loop in the state machine, until we have to wait for a result from the
2874  * server or have to sleep for throttling or \sleep.
2875  *
2876  * Note: In the switch-statement below, 'break' will loop back here,
2877  * meaning "continue in the state machine". Return is used to return to
2878  * the caller, giving the thread the opportunity to advance another
2879  * client.
2880  */
2881  for (;;)
2882  {
2883  Command *command;
2884 
2885  switch (st->state)
2886  {
2887  /* Select transaction (script) to run. */
2888  case CSTATE_CHOOSE_SCRIPT:
2889  st->use_file = chooseScript(thread);
2891 
2892  pg_log_debug("client %d executing script \"%s\"",
2893  st->id, sql_script[st->use_file].desc);
2894 
2895  /*
2896  * If time is over, we're done; otherwise, get ready to start
2897  * a new transaction, or to get throttled if that's requested.
2898  */
2901  break;
2902 
2903  /* Start new transaction (script) */
2904  case CSTATE_START_TX:
2905 
2906  /* establish connection if needed, i.e. under --connect */
2907  if (st->con == NULL)
2908  {
2909  instr_time start;
2910 
2912  start = now;
2913  if ((st->con = doConnect()) == NULL)
2914  {
2915  pg_log_error("client %d aborted while establishing connection", st->id);
2916  st->state = CSTATE_ABORTED;
2917  break;
2918  }
2920  INSTR_TIME_ACCUM_DIFF(thread->conn_time, now, start);
2921 
2922  /* Reset session-local state */
2923  memset(st->prepared, 0, sizeof(st->prepared));
2924  }
2925 
2926  /* record transaction start time */
2928  st->txn_begin = now;
2929 
2930  /*
2931  * When not throttling, this is also the transaction's
2932  * scheduled start time.
2933  */
2934  if (!throttle_delay)
2936 
2937  /* Begin with the first command */
2939  st->command = 0;
2940  break;
2941 
2942  /*
2943  * Handle throttling once per transaction by sleeping.
2944  */
2946 
2947  /*
2948  * Generate a delay such that the series of delays will
2949  * approximate a Poisson distribution centered on the
2950  * throttle_delay time.
2951  *
2952  * If transactions are too slow or a given wait is shorter
2953  * than a transaction, the next transaction will start right
2954  * away.
2955  */
2956  Assert(throttle_delay > 0);
2957 
2958  thread->throttle_trigger +=
2960  st->txn_scheduled = thread->throttle_trigger;
2961 
2962  /*
2963  * If --latency-limit is used, and this slot is already late
2964  * so that the transaction will miss the latency limit even if
2965  * it completed immediately, skip this time slot and schedule
2966  * to continue running on the next slot that isn't late yet.
2967  * But don't iterate beyond the -t limit, if one is given.
2968  */
2969  if (latency_limit)
2970  {
2971  int64 now_us;
2972 
2974  now_us = INSTR_TIME_GET_MICROSEC(now);
2975 
2976  while (thread->throttle_trigger < now_us - latency_limit &&
2977  (nxacts <= 0 || st->cnt < nxacts))
2978  {
2979  processXactStats(thread, st, &now, true, agg);
2980  /* next rendez-vous */
2981  thread->throttle_trigger +=
2983  st->txn_scheduled = thread->throttle_trigger;
2984  }
2985 
2986  /*
2987  * stop client if -t was exceeded in the previous skip
2988  * loop
2989  */
2990  if (nxacts > 0 && st->cnt >= nxacts)
2991  {
2992  st->state = CSTATE_FINISHED;
2993  break;
2994  }
2995  }
2996 
2997  /*
2998  * stop client if next transaction is beyond pgbench end of
2999  * execution; otherwise, throttle it.
3000  */
3001  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3003  break;
3004 
3005  /*
3006  * Wait until it's time to start next transaction.
3007  */
3008  case CSTATE_THROTTLE:
3010 
3011  if (INSTR_TIME_GET_MICROSEC(now) < st->txn_scheduled)
3012  return; /* still sleeping, nothing to do here */
3013 
3014  /* done sleeping, but don't start transaction if we're done */
3016  break;
3017 
3018  /*
3019  * Send a command to server (or execute a meta-command)
3020  */
3021  case CSTATE_START_COMMAND:
3022  command = sql_script[st->use_file].commands[st->command];
3023 
3024  /* Transition to script end processing if done */
3025  if (command == NULL)
3026  {
3027  st->state = CSTATE_END_TX;
3028  break;
3029  }
3030 
3031  /* record begin time of next command, and initiate it */
3032  if (report_per_command)
3033  {
3035  st->stmt_begin = now;
3036  }
3037 
3038  /* Execute the command */
3039  if (command->type == SQL_COMMAND)
3040  {
3041  if (!sendCommand(st, command))
3042  {
3043  commandFailed(st, "SQL", "SQL command send failed");
3044  st->state = CSTATE_ABORTED;
3045  }
3046  else
3047  st->state = CSTATE_WAIT_RESULT;
3048  }
3049  else if (command->type == META_COMMAND)
3050  {
3051  /*-----
3052  * Possible state changes when executing meta commands:
3053  * - on errors CSTATE_ABORTED
3054  * - on sleep CSTATE_SLEEP
3055  * - else CSTATE_END_COMMAND
3056  */
3057  st->state = executeMetaCommand(st, &now);
3058  }
3059 
3060  /*
3061  * We're now waiting for an SQL command to complete, or
3062  * finished processing a metacommand, or need to sleep, or
3063  * something bad happened.
3064  */
3065  Assert(st->state == CSTATE_WAIT_RESULT ||
3066  st->state == CSTATE_END_COMMAND ||
3067  st->state == CSTATE_SLEEP ||
3068  st->state == CSTATE_ABORTED);
3069  break;
3070 
3071  /*
3072  * non executed conditional branch
3073  */
3074  case CSTATE_SKIP_COMMAND:
3076  /* quickly skip commands until something to do... */
3077  while (true)
3078  {
3079  Command *command;
3080 
3081  command = sql_script[st->use_file].commands[st->command];
3082 
3083  /* cannot reach end of script in that state */
3084  Assert(command != NULL);
3085 
3086  /*
3087  * if this is conditional related, update conditional
3088  * state
3089  */
3090  if (command->type == META_COMMAND &&
3091  (command->meta == META_IF ||
3092  command->meta == META_ELIF ||
3093  command->meta == META_ELSE ||
3094  command->meta == META_ENDIF))
3095  {
3096  switch (conditional_stack_peek(st->cstack))
3097  {
3098  case IFSTATE_FALSE:
3099  if (command->meta == META_IF ||
3100  command->meta == META_ELIF)
3101  {
3102  /* we must evaluate the condition */
3104  }
3105  else if (command->meta == META_ELSE)
3106  {
3107  /* we must execute next command */
3111  st->command++;
3112  }
3113  else if (command->meta == META_ENDIF)
3114  {
3117  if (conditional_active(st->cstack))
3119 
3120  /*
3121  * else state remains in
3122  * CSTATE_SKIP_COMMAND
3123  */
3124  st->command++;
3125  }
3126  break;
3127 
3128  case IFSTATE_IGNORED:
3129  case IFSTATE_ELSE_FALSE:
3130  if (command->meta == META_IF)
3132  IFSTATE_IGNORED);
3133  else if (command->meta == META_ENDIF)
3134  {
3137  if (conditional_active(st->cstack))
3139  }
3140  /* could detect "else" & "elif" after "else" */
3141  st->command++;
3142  break;
3143 
3144  case IFSTATE_NONE:
3145  case IFSTATE_TRUE:
3146  case IFSTATE_ELSE_TRUE:
3147  default:
3148 
3149  /*
3150  * inconsistent if inactive, unreachable dead
3151  * code
3152  */
3153  Assert(false);
3154  }
3155  }
3156  else
3157  {
3158  /* skip and consider next */
3159  st->command++;
3160  }
3161 
3162  if (st->state != CSTATE_SKIP_COMMAND)
3163  /* out of quick skip command loop */
3164  break;
3165  }
3166  break;
3167 
3168  /*
3169  * Wait for the current SQL command to complete
3170  */
3171  case CSTATE_WAIT_RESULT:
3172  pg_log_debug("client %d receiving", st->id);
3173  if (!PQconsumeInput(st->con))
3174  {
3175  /* there's something wrong */
3176  commandFailed(st, "SQL", "perhaps the backend died while processing");
3177  st->state = CSTATE_ABORTED;
3178  break;
3179  }
3180  if (PQisBusy(st->con))
3181  return; /* don't have the whole result yet */
3182 
3183  /* store or discard the query results */
3185  st->state = CSTATE_END_COMMAND;
3186  else
3187  st->state = CSTATE_ABORTED;
3188  break;
3189 
3190  /*
3191  * Wait until sleep is done. This state is entered after a
3192  * \sleep metacommand. The behavior is similar to
3193  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3194  * instead of CSTATE_START_TX.
3195  */
3196  case CSTATE_SLEEP:
3198  if (INSTR_TIME_GET_MICROSEC(now) < st->sleep_until)
3199  return; /* still sleeping, nothing to do here */
3200  /* Else done sleeping. */
3201  st->state = CSTATE_END_COMMAND;
3202  break;
3203 
3204  /*
3205  * End of command: record stats and proceed to next command.
3206  */
3207  case CSTATE_END_COMMAND:
3208 
3209  /*
3210  * command completed: accumulate per-command execution times
3211  * in thread-local data structure, if per-command latencies
3212  * are requested.
3213  */
3214  if (report_per_command)
3215  {
3216  Command *command;
3217 
3219 
3220  command = sql_script[st->use_file].commands[st->command];
3221  /* XXX could use a mutex here, but we choose not to */
3222  addToSimpleStats(&command->stats,
3223  INSTR_TIME_GET_DOUBLE(now) -
3225  }
3226 
3227  /* Go ahead with next command, to be executed or skipped */
3228  st->command++;
3229  st->state = conditional_active(st->cstack) ?
3231  break;
3232 
3233  /*
3234  * End of transaction (end of script, really).
3235  */
3236  case CSTATE_END_TX:
3237 
3238  /* transaction finished: calculate latency and do log */
3239  processXactStats(thread, st, &now, false, agg);
3240 
3241  /*
3242  * missing \endif... cannot happen if CheckConditional was
3243  * okay
3244  */
3246 
3247  if (is_connect)
3248  {
3249  finishCon(st);
3250  INSTR_TIME_SET_ZERO(now);
3251  }
3252 
3253  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
3254  {
3255  /* script completed */
3256  st->state = CSTATE_FINISHED;
3257  break;
3258  }
3259 
3260  /* next transaction (script) */
3262 
3263  /*
3264  * Ensure that we always return on this point, so as to avoid
3265  * an infinite loop if the script only contains meta commands.
3266  */
3267  return;
3268 
3269  /*
3270  * Final states. Close the connection if it's still open.
3271  */
3272  case CSTATE_ABORTED:
3273  case CSTATE_FINISHED:
3274  finishCon(st);
3275  return;
3276  }
3277  }
3278 }
int64 throttle_trigger
Definition: pgbench.c:451
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:128
int type
Definition: pgbench.c:522
int id
Definition: pgbench.c:401
static int chooseScript(TState *thread)
Definition: pgbench.c:2618
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
#define pg_log_error(...)
Definition: logging.h:79
static bool readCommandResponse(CState *st, char *varprefix)
Definition: pgbench.c:2719
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:2610
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:1074
#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:6489
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:3288
#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:533
int64 cnt
Definition: pgbench.c:428
MetaCommand meta
Definition: pgbench.c:523
int64 txn_scheduled
Definition: pgbench.c:420
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:2637
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:528
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:1170
#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:526
volatile bool timer_exceeded
Definition: pgbench.c:251
Command ** commands
Definition: pgbench.c:535
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:951
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:3529
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 6657 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6658 {
6659  return (socket_set *) pg_malloc0(sizeof(socket_set));
6660 }
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 3775 of file pgbench.c.

References snprintf.

Referenced by createPartitions(), and initCreateTables().

3776 {
3777  snprintf(opts + strlen(opts), len - strlen(opts),
3778  " with (fillfactor=%d)", fillfactor);
3779 }
int fillfactor
Definition: pgbench.c:159
#define snprintf
Definition: port.h:192

◆ assignVariables()

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

Definition at line 1554 of file pgbench.c.

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

Referenced by sendCommand().

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

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

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

4694 {
4695  /* statically check conditional structure */
4697  int i;
4698 
4699  for (i = 0; ps.commands[i] != NULL; i++)
4700  {
4701  Command *cmd = ps.commands[i];
4702 
4703  if (cmd->type == META_COMMAND)
4704  {
4705  switch (cmd->meta)
4706  {
4707  case META_IF:
4709  break;
4710  case META_ELIF:
4711  if (conditional_stack_empty(cs))
4712  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4714  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4715  break;
4716  case META_ELSE:
4717  if (conditional_stack_empty(cs))
4718  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4720  ConditionError(ps.desc, i + 1, "\\else after \\else");
4722  break;
4723  case META_ENDIF:
4724  if (!conditional_stack_pop(cs))
4725  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4726  break;
4727  default:
4728  /* ignore anything else... */
4729  break;
4730  }
4731  }
4732  }
4733  if (!conditional_stack_empty(cs))
4734  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4736 }
int type
Definition: pgbench.c:522
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4682
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:533
MetaCommand meta
Definition: pgbench.c:523
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:535
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 4057 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4058 {
4059  if (initialize_steps[0] == '\0')
4060  {
4061  pg_log_fatal("no initialization steps specified");
4062  exit(1);
4063  }
4064 
4065  for (const char *step = initialize_steps; *step != '\0'; step++)
4066  {
4067  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4068  {
4069  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4070  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4071  exit(1);
4072  }
4073  }
4074 }
#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 2618 of file pgbench.c.

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

Referenced by advanceConnectionState().

2619 {
2620  int i = 0;
2621  int64 w;
2622 
2623  if (num_scripts == 1)
2624  return 0;
2625 
2626  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2627  do
2628  {
2629  w -= sql_script[i++].weight;
2630  } while (w >= 0);
2631 
2632  return i - 1;
2633 }
static int num_scripts
Definition: pgbench.c:540
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:847
int weight
Definition: pgbench.c:534
RandomState ts_choose_rs
Definition: pgbench.c:447
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
static int64 total_weight
Definition: pgbench.c:541
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6669 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6670 {
6671  FD_ZERO(&sa->fds);
6672  sa->maxfd = -1;
6673 }
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 1621 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

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

◆ coerceToDouble()

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

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

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

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

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2611 {
2612  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2613  st->id, st->command, cmd, st->use_file, message);
2614 }
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 1238 of file pgbench.c.

References name.

Referenced by lookupVariable().

1239 {
1240  return strcmp(((const Variable *) v1)->name,
1241  ((const Variable *) v2)->name);
1242 }
const char * name
Definition: encode.c:521

◆ computeIterativeZipfian()

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

Definition at line 973 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

974 {
975  double b = pow(2.0, s - 1.0);
976  double x,
977  t,
978  u,
979  v;
980 
981  /* Ensure n is sane */
982  if (n <= 1)
983  return 1;
984 
985  while (true)
986  {
987  /* random variates */
988  u = pg_erand48(random_state->xseed);
989  v = pg_erand48(random_state->xseed);
990 
991  x = floor(pow(u, -1.0 / (s - 1.0)));
992 
993  t = pow(1.0 + 1.0 / x, s - 1.0);
994  /* reject if too large or out of bound */
995  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
996  break;
997  }
998  return (int64) x;
999 }
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 4682 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

4683 {
4684  pg_log_fatal("condition error in script \"%s\" command %d: %s",
4685  desc, cmdn, msg);
4686  exit(1);
4687 }
#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 4417 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().

4418 {
4419  Command *my_command;
4420  char *p = skip_sql_comments(buf->data);
4421 
4422  if (p == NULL)
4423  return NULL;
4424 
4425  /* Allocate and initialize Command structure */
4426  my_command = (Command *) pg_malloc(sizeof(Command));
4427  initPQExpBuffer(&my_command->lines);
4428  appendPQExpBufferStr(&my_command->lines, p);
4429  my_command->first_line = NULL; /* this is set later */
4430  my_command->type = SQL_COMMAND;
4431  my_command->meta = META_NONE;
4432  my_command->argc = 0;
4433  memset(my_command->argv, 0, sizeof(my_command->argv));
4434  my_command->varprefix = NULL; /* allocated later, if needed */
4435  my_command->expr = NULL;
4436  initSimpleStats(&my_command->stats);
4437 
4438  return my_command;
4439 }
int type
Definition: pgbench.c:522
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:527
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4382
char * argv[MAX_ARGS]
Definition: pgbench.c:525
MetaCommand meta
Definition: pgbench.c:523
PQExpBufferData lines
Definition: pgbench.c:520
int argc
Definition: pgbench.c:524
#define SQL_COMMAND
Definition: pgbench.c:466
SimpleStats stats
Definition: pgbench.c:528
char * varprefix
Definition: pgbench.c:526
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1065
char * first_line
Definition: pgbench.c:521
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3609 of file pgbench.c.

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

Referenced by initCreateTables().

3610 {
3611  char ff[64];
3612 
3613  ff[0] = '\0';
3614 
3615  /*
3616  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3617  * pgbench_accounts.
3618  */
3619  append_fillfactor(ff, sizeof(ff));
3620 
3621  /* we must have to create some partitions */
3622  Assert(partitions > 0);
3623 
3624  fprintf(stderr, "creating %d partitions...\n", partitions);
3625 
3626  for (int p = 1; p <= partitions; p++)
3627  {
3628  char query[256];
3629 
3631  {
3632  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3633  char minvalue[32],
3634  maxvalue[32];
3635 
3636  /*
3637  * For RANGE, we use open-ended partitions at the beginning and
3638  * end to allow any valid value for the primary key. Although the
3639  * actual minimum and maximum values can be derived from the
3640  * scale, it is more generic and the performance is better.
3641  */
3642  if (p == 1)
3643  sprintf(minvalue, "minvalue");
3644  else
3645  sprintf(minvalue, INT64_FORMAT, (p - 1) * part_size + 1);
3646 
3647  if (p < partitions)
3648  sprintf(maxvalue, INT64_FORMAT, p * part_size + 1);
3649  else
3650  sprintf(maxvalue, "maxvalue");
3651 
3652  snprintf(query, sizeof(query),
3653  "create%s table pgbench_accounts_%d\n"
3654  " partition of pgbench_accounts\n"
3655  " for values from (%s) to (%s)%s\n",
3656  unlogged_tables ? " unlogged" : "", p,
3657  minvalue, maxvalue, ff);
3658  }
3659  else if (partition_method == PART_HASH)
3660  snprintf(query, sizeof(query),
3661  "create%s table pgbench_accounts_%d\n"
3662  " partition of pgbench_accounts\n"
3663  " for values with (modulus %d, remainder %d)%s\n",
3664  unlogged_tables ? " unlogged" : "", p,
3665  partitions, p - 1, ff);
3666  else /* cannot get there */
3667  Assert(0);
3668 
3669  executeStatement(con, query);
3670  }
3671 }
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:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139
#define sprintf
Definition: port.h:194
static void append_fillfactor(char *opts, int len)
Definition: pgbench.c:3775
#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:192

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3575 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

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

◆ doConnect()

static PGconn* doConnect ( void  )
static

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

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

3450 {
3451  FILE *logfile = thread->logfile;
3452 
3453  Assert(use_log);
3454 
3455  /*
3456  * Skip the log entry if sampling is enabled and this row doesn't belong
3457  * to the random sample.
3458  */
3459  if (sample_rate != 0.0 &&
3461  return;
3462 
3463  /* should we aggregate the results or not? */
3464  if (agg_interval > 0)
3465  {
3466  /*
3467  * Loop until we reach the interval of the current moment, and print
3468  * any empty intervals in between (this may happen with very low tps,
3469  * e.g. --rate=0.1).
3470  */
3471  time_t now = time(NULL);
3472 
3473  while (agg->start_time + agg_interval <= now)
3474  {
3475  /* print aggregated report to logfile */
3476  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3477  (long) agg->start_time,
3478  agg->cnt,
3479  agg->latency.sum,
3480  agg->latency.sum2,
3481  agg->latency.min,
3482  agg->latency.max);
3483  if (throttle_delay)
3484  {
3485  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3486  agg->lag.sum,
3487  agg->lag.sum2,
3488  agg->lag.min,
3489  agg->lag.max);
3490  if (latency_limit)
3491  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3492  }
3493  fputc('\n', logfile);
3494 
3495  /* reset data and move to next interval */
3496  initStats(agg, agg->start_time + agg_interval);
3497  }
3498 
3499  /* accumulate the current transaction */
3500  accumStats(agg, skipped, latency, lag);
3501  }
3502  else
3503  {
3504  /* no, print raw transactions */
3505  struct timeval tv;
3506 
3507  gettimeofday(&tv, NULL);
3508  if (skipped)
3509  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
3510  st->id, st->cnt, st->use_file,
3511  (long) tv.tv_sec, (long) tv.tv_usec);
3512  else
3513  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
3514  st->id, st->cnt, latency, st->use_file,
3515  (long) tv.tv_sec, (long) tv.tv_usec);
3516  if (throttle_delay)
3517  fprintf(logfile, " %.0f", lag);
3518  fputc('\n', logfile);
3519  }
3520 }
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:1105
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:196
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:1118
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 2408 of file pgbench.c.

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

Referenced by evaluateExpr().

2410 {
2411  if (isLazyFunc(func))
2412  return evalLazyFunc(st, func, args, retval);
2413  else
2414  return evalStandardFunc(st, func, args, retval);
2415 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1749
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1866
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1742

◆ evalLazyFunc()

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

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

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

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

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

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

Referenced by executeMetaCommand().

2824 {
2825  char *var;
2826  int usec;
2827 
2828  if (*argv[1] == ':')
2829  {
2830  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2831  {
2832  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
2833  return false;
2834  }
2835  usec = atoi(var);
2836  }
2837  else
2838  usec = atoi(argv[1]);
2839 
2840  if (argc > 2)
2841  {
2842  if (pg_strcasecmp(argv[2], "ms") == 0)
2843  usec *= 1000;
2844  else if (pg_strcasecmp(argv[2], "s") == 0)
2845  usec *= 1000000;
2846  }
2847  else
2848  usec *= 1000000;
2849 
2850  *usecs = usec;
2851  return true;
2852 }
#define pg_log_error(...)
Definition: logging.h:79
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1273
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 3288 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().

3289 {
3290  Command *command = sql_script[st->use_file].commands[st->command];
3291  int argc;
3292  char **argv;
3293 
3294  Assert(command != NULL && command->type == META_COMMAND);
3295 
3296  argc = command->argc;
3297  argv = command->argv;
3298 
3300  {
3302 
3303  initPQExpBuffer(&buf);
3304 
3305  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3306  for (int i = 1; i < argc; i++)
3307  appendPQExpBuffer(&buf, " %s", argv[i]);
3308 
3309  pg_log_debug("%s", buf.data);
3310 
3311  termPQExpBuffer(&buf);
3312  }
3313 
3314  if (command->meta == META_SLEEP)
3315  {
3316  int usec;
3317 
3318  /*
3319  * A \sleep doesn't execute anything, we just get the delay from the
3320  * argument, and enter the CSTATE_SLEEP state. (The per-command
3321  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3322  * delay has elapsed.)
3323  */
3324  if (!evaluateSleep(st, argc, argv, &usec))
3325  {
3326  commandFailed(st, "sleep", "execution of meta-command failed");
3327  return CSTATE_ABORTED;
3328  }
3329 
3331  st->sleep_until = INSTR_TIME_GET_MICROSEC(*now) + usec;
3332  return CSTATE_SLEEP;
3333  }
3334  else if (command->meta == META_SET)
3335  {
3336  PgBenchExpr *expr = command->expr;
3337  PgBenchValue result;
3338 
3339  if (!evaluateExpr(st, expr, &result))
3340  {
3341  commandFailed(st, argv[0], "evaluation of meta-command failed");
3342  return CSTATE_ABORTED;
3343  }
3344 
3345  if (!putVariableValue(st, argv[0], argv[1], &result))
3346  {
3347  commandFailed(st, "set", "assignment of meta-command failed");
3348  return CSTATE_ABORTED;
3349  }
3350  }
3351  else if (command->meta == META_IF)
3352  {
3353  /* backslash commands with an expression to evaluate */
3354  PgBenchExpr *expr = command->expr;
3355  PgBenchValue result;
3356  bool cond;
3357 
3358  if (!evaluateExpr(st, expr, &result))
3359  {
3360  commandFailed(st, argv[0], "evaluation of meta-command failed");
3361  return CSTATE_ABORTED;
3362  }
3363 
3364  cond = valueTruth(&result);
3366  }
3367  else if (command->meta == META_ELIF)
3368  {
3369  /* backslash commands with an expression to evaluate */
3370  PgBenchExpr *expr = command->expr;
3371  PgBenchValue result;
3372  bool cond;
3373 
3375  {
3376  /* elif after executed block, skip eval and wait for endif. */
3378  return CSTATE_END_COMMAND;
3379  }
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);
3390  }
3391  else if (command->meta == META_ELSE)
3392  {
3393  switch (conditional_stack_peek(st->cstack))
3394  {
3395  case IFSTATE_TRUE:
3397  break;
3398  case IFSTATE_FALSE: /* inconsistent if active */
3399  case IFSTATE_IGNORED: /* inconsistent if active */
3400  case IFSTATE_NONE: /* else without if */
3401  case IFSTATE_ELSE_TRUE: /* else after else */
3402  case IFSTATE_ELSE_FALSE: /* else after else */
3403  default:
3404  /* dead code if conditional check is ok */
3405  Assert(false);
3406  }
3407  }
3408  else if (command->meta == META_ENDIF)
3409  {
3412  }
3413  else if (command->meta == META_SETSHELL)
3414  {
3415  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3416  {
3417  commandFailed(st, "setshell", "execution of meta-command failed");
3418  return CSTATE_ABORTED;
3419  }
3420  }
3421  else if (command->meta == META_SHELL)
3422  {
3423  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3424  {
3425  commandFailed(st, "shell", "execution of meta-command failed");
3426  return CSTATE_ABORTED;
3427  }
3428  }
3429 
3430  /*
3431  * executing the expression or shell command might have taken a
3432  * non-negligible amount of time, so reset 'now'
3433  */
3435 
3436  return CSTATE_END_COMMAND;
3437 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int type
Definition: pgbench.c:522
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:2610
PgBenchExpr * expr
Definition: pgbench.c:527
#define INSTR_TIME_SET_ZERO(t)
Definition: instr_time.h:154
char * argv[MAX_ARGS]
Definition: pgbench.c:525
ConditionalStack cstack
Definition: pgbench.c:403
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2424
#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:523
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:539
enum pg_log_level __pg_log_level
Definition: logging.c:16
int argc
Definition: pgbench.c:524
int command
Definition: pgbench.c:412
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2502
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:2823
#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:1641
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:535
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:1474
#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 1139 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().

1140 {
1141  PGresult *res;
1142 
1143  res = PQexec(con, sql);
1144  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1145  {
1146  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1147  pg_log_info("query was: %s", sql);
1148  exit(1);
1149  }
1150  PQclear(res);
1151 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6684
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 4961 of file pgbench.c.

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

Referenced by main().

4962 {
4963  int i,
4964  found = 0,
4965  len = strlen(name);
4966  const BuiltinScript *result = NULL;
4967 
4968  for (i = 0; i < lengthof(builtin_script); i++)
4969  {
4970  if (strncmp(builtin_script[i].name, name, len) == 0)
4971  {
4972  result = &builtin_script[i];
4973  found++;
4974  }
4975  }
4976 
4977  /* ok, unambiguous result */
4978  if (found == 1)
4979  return result;
4980 
4981  /* error cases */
4982  if (found == 0)
4983  pg_log_fatal("no builtin script found for name \"%s\"", name);
4984  else /* found > 1 */
4985  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
4986 
4988  exit(1);
4989 }
static void listAvailableScripts(void)
Definition: pgbench.c:4949
#define lengthof(array)
Definition: c.h:668
static const BuiltinScript builtin_script[]
Definition: pgbench.c:551
const char * name
Definition: encode.c:521
int i
#define pg_log_fatal(...)
Definition: logging.h:75

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6489 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6490 {
6491  if (st->con != NULL)
6492  {
6493  PQfinish(st->con);
6494  st->con = NULL;
6495  }
6496 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4182
PGconn * con
Definition: pgbench.c:400

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4443 of file pgbench.c.

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

Referenced by ParseScript().

4444 {
4445  termPQExpBuffer(&command->lines);
4446  if (command->first_line)
4447  pg_free(command->first_line);
4448  for (int i = 0; i < command->argc; i++)
4449  pg_free(command->argv[i]);
4450  if (command->varprefix)
4451  pg_free(command->varprefix);
4452 
4453  /*
4454  * It should also free expr recursively, but this is currently not needed
4455  * as only gset commands (which do not have an expression) are freed.
4456  */
4457  pg_free(command);
4458 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:525
PQExpBufferData lines
Definition: pgbench.c:520
int argc
Definition: pgbench.c:524
char * varprefix
Definition: pgbench.c:526
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:521

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6663 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6664 {
6665  pg_free(sa);
6666 }
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 867 of file pgbench.c.

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

Referenced by evalStandardFunc().

869 {
870  double cut,
871  uniform,
872  rand;
873 
874  /* abort if wrong parameter, but must really be checked beforehand */
875  Assert(parameter > 0.0);
876  cut = exp(-parameter);
877  /* erand in [0, 1), uniform in (0, 1] */
878  uniform = 1.0 - pg_erand48(random_state->xseed);
879 
880  /*
881  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
882  */
883  Assert((1.0 - cut) != 0.0);
884  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
885  /* return int64 random number within between min and max */
886  return min + (int64) ((max - min + 1) * rand);
887 }
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 891 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1018 {
1019  int64 result;
1020  int i;
1021 
1022  result = FNV_OFFSET_BASIS ^ seed;
1023  for (i = 0; i < 8; ++i)
1024  {
1025  int32 octet = val & 0xff;
1026 
1027  val = val >> 8;
1028  result = result ^ octet;
1029  result = result * FNV_PRIME;
1030  }
1031 
1032  return result;
1033 }
#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 1042 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1043 {
1044  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1045  uint64 k = (uint64) val;
1046 
1047  k *= MM2_MUL;
1048  k ^= k >> MM2_ROT;
1049  k *= MM2_MUL;
1050 
1051  result ^= k;
1052  result *= MM2_MUL;
1053 
1054  result ^= result >> MM2_ROT;
1055  result *= MM2_MUL;
1056  result ^= result >> MM2_ROT;
1057 
1058  return (int64) result;
1059 }
#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 2468 of file pgbench.c.

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

Referenced by process_backslash_command().

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

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

952 {
953  /*
954  * Use inverse transform sampling to generate a value > 0, such that the
955  * expected (i.e. average) value is the given argument.
956  */
957  double uniform;
958 
959  /* erand in [0, 1), uniform in (0, 1] */
960  uniform = 1.0 - pg_erand48(random_state->xseed);
961 
962  return (int64) (-log(uniform) * center + 0.5);
963 }
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 1590 of file pgbench.c.

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

Referenced by sendCommand().

1591 {
1592  int i;
1593 
1594  for (i = 0; i < command->argc - 1; i++)
1595  params[i] = getVariable(st, command->argv[i + 1]);
1596 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1273
char * argv[MAX_ARGS]
Definition: pgbench.c:525
int argc
Definition: pgbench.c:524
int i

◆ getrand()

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

Definition at line 847 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

848 {
849  /*
850  * Odd coding is so that min and max have approximately the same chance of
851  * being selected as do numbers between them.
852  *
853  * pg_erand48() is thread-safe and concurrent, which is why we use it
854  * rather than random(), which in glibc is non-reentrant, and therefore
855  * protected by a mutex, and therefore a bottleneck on machines with many
856  * CPUs.
857  */
858  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
859 }
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 4172 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().

4173 {
4174  PGresult *res;
4175 
4176  /*
4177  * get the scaling factor that should be same as count(*) from
4178  * pgbench_branches if this is not a custom query
4179  */
4180  res = PQexec(con, "select count(*) from pgbench_branches");
4181  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4182  {
4183  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4184 
4185  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4186 
4187  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4188  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4189  PQdb(con));
4190 
4191  exit(1);
4192  }
4193  scale = atoi(PQgetvalue(res, 0, 0));
4194  if (scale < 0)
4195  {
4196  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4197  PQgetvalue(res, 0, 0));
4198  exit(1);
4199  }
4200  PQclear(res);
4201 
4202  /* warn if we override user-given -s switch */
4203  if (scale_given)
4204  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4205  scale);
4206 
4207  /*
4208  * Get the partition information for the first "pgbench_accounts" table
4209  * found in search_path.
4210  *
4211  * The result is empty if no "pgbench_accounts" is found.
4212  *
4213  * Otherwise, it always returns one row even if the table is not
4214  * partitioned (in which case the partition strategy is NULL).
4215  *
4216  * The number of partitions can be 0 even for partitioned tables, if no
4217  * partition is attached.
4218  *
4219  * We assume no partitioning on any failure, so as to avoid failing on an
4220  * old version without "pg_partitioned_table".
4221  */
4222  res = PQexec(con,
4223  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4224  "from pg_catalog.pg_class as c "
4225  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4226  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4227  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4228  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4229  "where c.relname = 'pgbench_accounts' and o.n is not null "
4230  "group by 1, 2 "
4231  "order by 1 asc "
4232  "limit 1");
4233 
4234  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4235  {
4236  /* probably an older version, coldly assume no partitioning */
4238  partitions = 0;
4239  }
4240  else if (PQntuples(res) == 0)
4241  {
4242  /*
4243  * This case is unlikely as pgbench already found "pgbench_branches"
4244  * above to compute the scale.
4245  */
4246  pg_log_fatal("no pgbench_accounts table found in search_path");
4247  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4248  exit(1);
4249  }
4250  else /* PQntupes(res) == 1 */
4251  {
4252  /* normal case, extract partition information */
4253  if (PQgetisnull(res, 0, 1))
4255  else
4256  {
4257  char *ps = PQgetvalue(res, 0, 1);
4258 
4259  /* column must be there */
4260  Assert(ps != NULL);
4261 
4262  if (strcmp(ps, "r") == 0)
4264  else if (strcmp(ps, "h") == 0)
4266  else
4267  {
4268  /* possibly a newer version with new partition method */
4269  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4270  exit(1);
4271  }
4272  }
4273 
4274  partitions = atoi(PQgetvalue(res, 0, 2));
4275  }
4276 
4277  PQclear(res);
4278 }
static int partitions
Definition: pgbench.c:195
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6684
#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:6534
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 1273 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().

1274 {
1275  Variable *var;
1276  char stringform[64];
1277 
1278  var = lookupVariable(st, name);
1279  if (var == NULL)
1280  return NULL; /* not found */
1281 
1282  if (var->svalue)
1283  return var->svalue; /* we have it in string form */
1284 
1285  /* We need to produce a string equivalent of the value */
1286  Assert(var->value.type != PGBT_NO_VALUE);
1287  if (var->value.type == PGBT_NULL)
1288  snprintf(stringform, sizeof(stringform), "NULL");
1289  else if (var->value.type == PGBT_BOOLEAN)
1290  snprintf(stringform, sizeof(stringform),
1291  "%s", var->value.u.bval ? "true" : "false");
1292  else if (var->value.type == PGBT_INT)
1293  snprintf(stringform, sizeof(stringform),
1294  INT64_FORMAT, var->value.u.ival);
1295  else if (var->value.type == PGBT_DOUBLE)
1296  snprintf(stringform, sizeof(stringform),
1297  "%.*g", DBL_DIG, var->value.u.dval);
1298  else /* internal error, unexpected type */
1299  Assert(0);
1300  var->svalue = pg_strdup(stringform);
1301  return var->svalue;
1302 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1246
union PgBenchValue::@39 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:521
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:192

◆ getZipfianRand()

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

Definition at line 1003 of file pgbench.c.

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

Referenced by evalStandardFunc().

1004 {
1005  int64 n = max - min + 1;
1006 
1007  /* abort if parameter is invalid */
1009 
1010  return min - 1 + computeIterativeZipfian(random_state, n, s);
1011 }
#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:973

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6505 of file pgbench.c.

Referenced by setalarm().

6506 {
6507  timer_exceeded = true;
6508 }
volatile bool timer_exceeded
Definition: pgbench.c:251

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4031 of file pgbench.c.

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

Referenced by runInitSteps().

4032 {
4033  static const char *const DDLKEYs[] = {
4034  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4035  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4036  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4037  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4038  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4039  };
4040  int i;
4041 
4042  fprintf(stderr, "creating foreign keys...\n");
4043  for (i = 0; i < lengthof(DDLKEYs); i++)
4044  {
4045  executeStatement(con, DDLKEYs[i]);
4046  }
4047 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 3996 of file pgbench.c.

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

Referenced by runInitSteps().

3997 {
3998  static const char *const DDLINDEXes[] = {
3999  "alter table pgbench_branches add primary key (bid)",
4000  "alter table pgbench_tellers add primary key (tid)",
4001  "alter table pgbench_accounts add primary key (aid)"
4002  };
4003  int i;
4004 
4005  fprintf(stderr, "creating primary keys...\n");
4006  for (i = 0; i < lengthof(DDLINDEXes); i++)
4007  {
4008  char buffer[256];
4009 
4010  strlcpy(buffer, DDLINDEXes[i], sizeof(buffer));
4011 
4012  if (index_tablespace != NULL)
4013  {
4014  char *escape_tablespace;
4015 
4016  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4017  strlen(index_tablespace));
4018  snprintf(buffer + strlen(buffer), sizeof(buffer) - strlen(buffer),
4019  " using index tablespace %s", escape_tablespace);
4020  PQfreemem(escape_tablespace);
4021  }
4022 
4023  executeStatement(con, buffer);
4024  }
4025 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139
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:192
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

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

3678 {
3679  /*
3680  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
3681  * fields in these table declarations were intended to comply with that.
3682  * The pgbench_accounts table complies with that because the "filler"
3683  * column is set to blank-padded empty string. But for all other tables
3684  * the columns default to NULL and so don't actually take any space. We
3685  * could fix that by giving them non-null default values. However, that
3686  * would completely break comparability of pgbench results with prior
3687  * versions. Since pgbench has never pretended to be fully TPC-B compliant
3688  * anyway, we stick with the historical behavior.
3689  */
3690  struct ddlinfo
3691  {
3692  const char *table; /* table name */
3693  const char *smcols; /* column decls if accountIDs are 32 bits */
3694  const char *bigcols; /* column decls if accountIDs are 64 bits */
3695  int declare_fillfactor;
3696  };
3697  static const struct ddlinfo DDLs[] = {
3698  {
3699  "pgbench_history",
3700  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
3701  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
3702  0
3703  },
3704  {
3705  "pgbench_tellers",
3706  "tid int not null,bid int,tbalance int,filler char(84)",
3707  "tid int not null,bid int,tbalance int,filler char(84)",
3708  1
3709  },
3710  {
3711  "pgbench_accounts",
3712  "aid int not null,bid int,abalance int,filler char(84)",
3713  "aid bigint not null,bid int,abalance int,filler char(84)",
3714  1
3715  },
3716  {
3717  "pgbench_branches",
3718  "bid int not null,bbalance int,filler char(88)",
3719  "bid int not null,bbalance int,filler char(88)",
3720  1
3721  }
3722  };
3723  int i;
3724 
3725  fprintf(stderr, "creating tables...\n");
3726 
3727  for (i = 0; i < lengthof(DDLs); i++)
3728  {
3729  char opts[256];
3730  char buffer[256];
3731  const struct ddlinfo *ddl = &DDLs[i];
3732  const char *cols;
3733 
3734  /* Construct new create table statement. */
3735  opts[0] = '\0';
3736 
3737  /* Partition pgbench_accounts table */
3738  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
3739  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3740  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
3741  else if (ddl->declare_fillfactor)
3742  /* fillfactor is only expected on actual tables */
3743  append_fillfactor(opts, sizeof(opts));
3744 
3745  if (tablespace != NULL)
3746  {
3747  char *escape_tablespace;
3748 
3749  escape_tablespace = PQescapeIdentifier(con, tablespace,
3750  strlen(tablespace));
3751  snprintf(opts + strlen(opts), sizeof(opts) - strlen(opts),
3752  " tablespace %s", escape_tablespace);
3753  PQfreemem(escape_tablespace);
3754  }
3755 
3756  cols = (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols;
3757 
3758  snprintf(buffer, sizeof(buffer), "create%s table %s(%s)%s",
3759  unlogged_tables ? " unlogged" : "",
3760  ddl->table, cols, opts);
3761 
3762  executeStatement(con, buffer);
3763  }
3764 
3765  if (partition_method != PART_NONE)
3766  createPartitions(con);
3767 }
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:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139
#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:3775
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:3609
#define snprintf
Definition: port.h:192
void PQfreemem(void *ptr)
Definition: fe-exec.c:3296

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3587 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

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

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

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

3799 {
3800  char sql[256];
3801  PGresult *res;
3802  int i;
3803  int64 k;
3804 
3805  /* used to track elapsed time and estimate of the remaining time */
3806  instr_time start,
3807  diff;
3808  double elapsed_sec,
3809  remaining_sec;
3810  int log_interval = 1;
3811 
3812  /* Stay on the same line if reporting to a terminal */
3813  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
3814 
3815  fprintf(stderr, "generating data (client-side)...\n");
3816 
3817  /*
3818  * we do all of this in one transaction to enable the backend's
3819  * data-loading optimizations
3820  */
3821  executeStatement(con, "begin");
3822 
3823  /* truncate away any old data */
3824  initTruncateTables(con);
3825 
3826  /*
3827  * fill branches, tellers, accounts in that order in case foreign keys
3828  * already exist
3829  */
3830  for (i = 0; i < nbranches * scale; i++)
3831  {
3832  /* "filler" column defaults to NULL */
3833  snprintf(sql, sizeof(sql),
3834  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
3835  i + 1);
3836  executeStatement(con, sql);
3837  }
3838 
3839  for (i = 0; i < ntellers * scale; i++)
3840  {
3841  /* "filler" column defaults to NULL */
3842  snprintf(sql, sizeof(sql),
3843  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
3844  i + 1, i / ntellers + 1);
3845  executeStatement(con, sql);
3846  }
3847 
3848  /*
3849  * accounts is big enough to be worth using COPY and tracking runtime
3850  */
3851  res = PQexec(con, "copy pgbench_accounts from stdin");
3852  if (PQresultStatus(res) != PGRES_COPY_IN)
3853  {
3854  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
3855  exit(1);
3856  }
3857  PQclear(res);
3858 
3859  INSTR_TIME_SET_CURRENT(start);
3860 
3861  for (k = 0; k < (int64) naccounts * scale; k++)
3862  {
3863  int64 j = k + 1;
3864 
3865  /* "filler" column defaults to blank padded empty string */
3866  snprintf(sql, sizeof(sql),
3867  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
3868  j, k / naccounts + 1, 0);
3869  if (PQputline(con, sql))
3870  {
3871  pg_log_fatal("PQputline failed");
3872  exit(1);
3873  }
3874 
3875  if (CancelRequested)
3876  break;
3877 
3878  /*
3879  * If we want to stick with the original logging, print a message each
3880  * 100k inserted rows.
3881  */
3882  if ((!use_quiet) && (j % 100000 == 0))
3883  {
3884  INSTR_TIME_SET_CURRENT(diff);
3885  INSTR_TIME_SUBTRACT(diff, start);
3886 
3887  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3888  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3889 
3890  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3891  j, (int64) naccounts * scale,
3892  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
3893  elapsed_sec, remaining_sec, eol);
3894  }
3895  /* let's not call the timing for each row, but only each 100 rows */
3896  else if (use_quiet && (j % 100 == 0))
3897  {
3898  INSTR_TIME_SET_CURRENT(diff);
3899  INSTR_TIME_SUBTRACT(diff, start);
3900 
3901  elapsed_sec = INSTR_TIME_GET_DOUBLE(diff);
3902  remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
3903 
3904  /* have we reached the next interval (or end)? */
3905  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
3906  {
3907  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
3908  j, (int64) naccounts * scale,
3909  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
3910 
3911  /* skip to the next interval */
3912  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
3913  }
3914  }
3915  }
3916 
3917  if (eol != '\n')
3918  fputc('\n', stderr); /* Need to move to next line */
3919 
3920  if (PQputline(con, "\\.\n"))
3921  {
3922  pg_log_fatal("very last PQputline failed");
3923  exit(1);
3924  }
3925  if (PQendcopy(con))
3926  {
3927  pg_log_fatal("PQendcopy failed");
3928  exit(1);
3929  }
3930 
3931  executeStatement(con, "commit");
3932 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6684
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:196
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:1139
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:3785
#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:192
#define pg_log_fatal(...)
Definition: logging.h:75

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 3942 of file pgbench.c.

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

Referenced by runInitSteps().

3943 {
3944  char sql[256];
3945 
3946  fprintf(stderr, "generating data (server-side)...\n");
3947 
3948  /*
3949  * we do all of this in one transaction to enable the backend's
3950  * data-loading optimizations
3951  */
3952  executeStatement(con, "begin");
3953 
3954  /* truncate away any old data */
3955  initTruncateTables(con);
3956 
3957  snprintf(sql, sizeof(sql),
3958  "insert into pgbench_branches(bid,bbalance) "
3959  "select bid, 0 "
3960  "from generate_series(1, %d) as bid", nbranches * scale);
3961  executeStatement(con, sql);
3962 
3963  snprintf(sql, sizeof(sql),
3964  "insert into pgbench_tellers(tid,bid,tbalance) "
3965  "select tid, (tid - 1) / %d + 1, 0 "
3966  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
3967  executeStatement(con, sql);
3968 
3969  snprintf(sql, sizeof(sql),
3970  "insert into pgbench_accounts(aid,bid,abalance,filler) "
3971  "select aid, (aid - 1) / %d + 1, 0, '' "
3972  "from generate_series(1, "INT64_FORMAT") as aid",
3973  naccounts, (int64) naccounts * scale);
3974  executeStatement(con, sql);
3975 
3976  executeStatement(con, "commit");
3977 }
int scale
Definition: pgbench.c:153
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139
#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:3785
#define INT64_FORMAT
Definition: c.h:409
#define snprintf
Definition: port.h:192

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 828 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

829 {
830  random_state->xseed[0] = (unsigned short)
832  random_state->xseed[1] = (unsigned short)
834  random_state->xseed[2] = (unsigned short)
836 }
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 1065 of file pgbench.c.

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

1066 {
1067  memset(ss, 0, sizeof(SimpleStats));
1068 }

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

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

1106 {
1107  sd->start_time = start_time;
1108  sd->cnt = 0;
1109  sd->skipped = 0;
1110  initSimpleStats(&sd->latency);
1111  initSimpleStats(&sd->lag);
1112 }
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:1065

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 3785 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

3786 {
3787  executeStatement(con, "truncate table "
3788  "pgbench_accounts, "
3789  "pgbench_branches, "
3790  "pgbench_history, "
3791  "pgbench_tellers");
3792 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 3983 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3984 {
3985  fprintf(stderr, "vacuuming...\n");
3986  executeStatement(con, "vacuum analyze pgbench_branches");
3987  executeStatement(con, "vacuum analyze pgbench_tellers");
3988  executeStatement(con, "vacuum analyze pgbench_accounts");
3989  executeStatement(con, "vacuum analyze pgbench_history");
3990 }
#define fprintf
Definition: port.h:196
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1139

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 691 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

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

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1742 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1743 {
1744  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1745 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4949 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4950 {
4951  int i;
4952 
4953  fprintf(stderr, "Available builtin scripts:\n");
4954  for (i = 0; i < lengthof(builtin_script); i++)
4955  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4956  fprintf(stderr, "\n");
4957 }
#define lengthof(array)
Definition: c.h:668
#define fprintf
Definition: port.h:196
static const BuiltinScript builtin_script[]
Definition: pgbench.c:551
const char * name
Definition: encode.c:521
int i

◆ lookupCreateVariable()

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

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

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

◆ lookupVariable()

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

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

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

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5355 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.

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