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

Go to the source code of this file.

Data Structures

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

Macros

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

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef struct StatsData StatsData
 
typedef struct RandomState RandomState
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 

Enumerations

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

Functions

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

Variables

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

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

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

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 139 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 80 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 79 of file pgbench.c.

Referenced by getHashFnv1a().

◆ INVALID_THREAD

#define INVALID_THREAD   ((pthread_t) 0)

Definition at line 462 of file pgbench.c.

Referenced by main().

◆ LOG_STEP_SECONDS

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

Definition at line 138 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 71 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 474 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 1874 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2619 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 271 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

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

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 81 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 82 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

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

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

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

Referenced by main(), and socket_has_input().

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 228 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 272 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 102 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ WSEP

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

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

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

◆ MetaCommand

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

Definition at line 476 of file pgbench.c.

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

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 199 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 491 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1121 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

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

◆ add_socket_to_set()

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

Definition at line 6713 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6714 {
6715  if (fd < 0 || fd >= FD_SETSIZE)
6716  {
6717  /*
6718  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
6719  * complicating the API to make it less grotty.
6720  */
6721  pg_log_fatal("too many client connections for select()");
6722  exit(1);
6723  }
6724  FD_SET(fd, &sa->fds);
6725  if (fd > sa->maxfd)
6726  sa->maxfd = fd;
6727 }
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:107
int maxfd
Definition: pgbench.c:106
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5077 of file pgbench.c.

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

Referenced by ParseScript().

5078 {
5079  if (script.commands == NULL || script.commands[0] == NULL)
5080  {
5081  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5082  exit(1);
5083  }
5084 
5085  if (num_scripts >= MAX_SCRIPTS)
5086  {
5087  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5088  exit(1);
5089  }
5090 
5091  CheckConditional(script);
5092 
5093  sql_script[num_scripts] = script;
5094  num_scripts++;
5095 }
static int num_scripts
Definition: pgbench.c:544
#define MAX_SCRIPTS
Definition: pgbench.c:271
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:4727
const char * desc
Definition: pgbench.c:537
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
Command ** commands
Definition: pgbench.c:539
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1077 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

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

◆ advanceConnectionState()

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

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

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

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 6694 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

6695 {
6696  return (socket_set *) pg_malloc0(sizeof(socket_set));
6697 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ assignVariables()

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

Definition at line 1569 of file pgbench.c.

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

Referenced by sendCommand().

1570 {
1571  char *p,
1572  *name,
1573  *val;
1574 
1575  p = sql;
1576  while ((p = strchr(p, ':')) != NULL)
1577  {
1578  int eaten;
1579 
1580  name = parseVariable(p, &eaten);
1581  if (name == NULL)
1582  {
1583  while (*p == ':')
1584  {
1585  p++;
1586  }
1587  continue;
1588  }
1589 
1590  val = getVariable(st, name);
1591  free(name);
1592  if (val == NULL)
1593  {
1594  p++;
1595  continue;
1596  }
1597 
1598  p = replaceVariable(&sql, p, eaten, val);
1599  }
1600 
1601  return sql;
1602 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1549
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1522
const char * name
Definition: encode.c:515
long val
Definition: informix.c:664

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

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

4728 {
4729  /* statically check conditional structure */
4731  int i;
4732 
4733  for (i = 0; ps.commands[i] != NULL; i++)
4734  {
4735  Command *cmd = ps.commands[i];
4736 
4737  if (cmd->type == META_COMMAND)
4738  {
4739  switch (cmd->meta)
4740  {
4741  case META_IF:
4743  break;
4744  case META_ELIF:
4745  if (conditional_stack_empty(cs))
4746  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
4748  ConditionError(ps.desc, i + 1, "\\elif after \\else");
4749  break;
4750  case META_ELSE:
4751  if (conditional_stack_empty(cs))
4752  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
4754  ConditionError(ps.desc, i + 1, "\\else after \\else");
4756  break;
4757  case META_ENDIF:
4758  if (!conditional_stack_pop(cs))
4759  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
4760  break;
4761  default:
4762  /* ignore anything else... */
4763  break;
4764  }
4765  }
4766  }
4767  if (!conditional_stack_empty(cs))
4768  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
4770 }
int type
Definition: pgbench.c:526
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:4716
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:468
const char * desc
Definition: pgbench.c:537
MetaCommand meta
Definition: pgbench.c:527
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:539
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 4091 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4092 {
4093  if (initialize_steps[0] == '\0')
4094  {
4095  pg_log_fatal("no initialization steps specified");
4096  exit(1);
4097  }
4098 
4099  for (const char *step = initialize_steps; *step != '\0'; step++)
4100  {
4101  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4102  {
4103  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4104  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4105  exit(1);
4106  }
4107  }
4108 }
#define ALL_INIT_STEPS
Definition: pgbench.c:136
#define pg_log_info(...)
Definition: logging.h:88
#define pg_log_fatal(...)
Definition: logging.h:76

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 2635 of file pgbench.c.

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

Referenced by advanceConnectionState().

2636 {
2637  int i = 0;
2638  int64 w;
2639 
2640  if (num_scripts == 1)
2641  return 0;
2642 
2643  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2644  do
2645  {
2646  w -= sql_script[i++].weight;
2647  } while (w >= 0);
2648 
2649  return i - 1;
2650 }
static int num_scripts
Definition: pgbench.c:544
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:850
int weight
Definition: pgbench.c:538
RandomState ts_choose_rs
Definition: pgbench.c:448
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:543
static int64 total_weight
Definition: pgbench.c:545
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 6706 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

6707 {
6708  FD_ZERO(&sa->fds);
6709  sa->maxfd = -1;
6710 }
fd_set fds
Definition: pgbench.c:107
int maxfd
Definition: pgbench.c:106

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1636 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1637 {
1638  if (pval->type == PGBT_BOOLEAN)
1639  {
1640  *bval = pval->u.bval;
1641  return true;
1642  }
1643  else /* NULL, INT or DOUBLE */
1644  {
1645  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1646  *bval = false; /* suppress uninitialized-variable warnings */
1647  return false;
1648  }
1649 }
#define pg_log_error(...)
Definition: logging.h:80
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1614
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
union PgBenchValue::@36 u

◆ coerceToDouble()

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

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

1706 {
1707  if (pval->type == PGBT_DOUBLE)
1708  {
1709  *dval = pval->u.dval;
1710  return true;
1711  }
1712  else if (pval->type == PGBT_INT)
1713  {
1714  *dval = (double) pval->u.ival;
1715  return true;
1716  }
1717  else /* BOOLEAN or NULL */
1718  {
1719  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1720  return false;
1721  }
1722 }
#define pg_log_error(...)
Definition: logging.h:80
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1614
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
union PgBenchValue::@36 u
int64 ival
Definition: pgbench.h:49

◆ coerceToInt()

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

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

1678 {
1679  if (pval->type == PGBT_INT)
1680  {
1681  *ival = pval->u.ival;
1682  return true;
1683  }
1684  else if (pval->type == PGBT_DOUBLE)
1685  {
1686  double dval = rint(pval->u.dval);
1687 
1688  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1689  {
1690  pg_log_error("double to int overflow for %f", dval);
1691  return false;
1692  }
1693  *ival = (int64) dval;
1694  return true;
1695  }
1696  else /* BOOLEAN or NULL */
1697  {
1698  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1699  return false;
1700  }
1701 }
#define pg_log_error(...)
Definition: logging.h:80
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1095
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1614
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
union PgBenchValue::@36 u
int64 ival
Definition: pgbench.h:49

◆ commandFailed()

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

Definition at line 2627 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2628 {
2629  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2630  st->id, st->command, cmd, st->use_file, message);
2631 }
int id
Definition: pgbench.c:402
#define pg_log_error(...)
Definition: logging.h:80
int command
Definition: pgbench.c:413
int use_file
Definition: pgbench.c:412

◆ compareVariableNames()

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

Definition at line 1239 of file pgbench.c.

References name.

Referenced by lookupVariable().

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

◆ computeIterativeZipfian()

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

Definition at line 976 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

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

◆ ConditionError()

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

Definition at line 4716 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

4717 {
4718  pg_log_fatal("condition error in script \"%s\" command %d: %s",
4719  desc, cmdn, msg);
4720  exit(1);
4721 }
#define pg_log_fatal(...)
Definition: logging.h:76

◆ create_sql_command()

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

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

4452 {
4453  Command *my_command;
4454  char *p = skip_sql_comments(buf->data);
4455 
4456  if (p == NULL)
4457  return NULL;
4458 
4459  /* Allocate and initialize Command structure */
4460  my_command = (Command *) pg_malloc(sizeof(Command));
4461  initPQExpBuffer(&my_command->lines);
4462  appendPQExpBufferStr(&my_command->lines, p);
4463  my_command->first_line = NULL; /* this is set later */
4464  my_command->type = SQL_COMMAND;
4465  my_command->meta = META_NONE;
4466  my_command->argc = 0;
4467  memset(my_command->argv, 0, sizeof(my_command->argv));
4468  my_command->varprefix = NULL; /* allocated later, if needed */
4469  my_command->expr = NULL;
4470  initSimpleStats(&my_command->stats);
4471 
4472  return my_command;
4473 }
int type
Definition: pgbench.c:526
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:531
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4416
char * argv[MAX_ARGS]
Definition: pgbench.c:529
MetaCommand meta
Definition: pgbench.c:527
PQExpBufferData lines
Definition: pgbench.c:524
int argc
Definition: pgbench.c:528
#define SQL_COMMAND
Definition: pgbench.c:467
SimpleStats stats
Definition: pgbench.c:532
char * varprefix
Definition: pgbench.c:530
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1068
char * first_line
Definition: pgbench.c:525
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3644 of file pgbench.c.

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

Referenced by initCreateTables().

3645 {
3646  PQExpBufferData query;
3647 
3648  /* we must have to create some partitions */
3649  Assert(partitions > 0);
3650 
3651  fprintf(stderr, "creating %d partitions...\n", partitions);
3652 
3653  initPQExpBuffer(&query);
3654 
3655  for (int p = 1; p <= partitions; p++)
3656  {
3658  {
3659  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3660 
3661  printfPQExpBuffer(&query,
3662  "create%s table pgbench_accounts_%d\n"
3663  " partition of pgbench_accounts\n"
3664  " for values from (",
3665  unlogged_tables ? " unlogged" : "", p);
3666 
3667  /*
3668  * For RANGE, we use open-ended partitions at the beginning and
3669  * end to allow any valid value for the primary key. Although the
3670  * actual minimum and maximum values can be derived from the
3671  * scale, it is more generic and the performance is better.
3672  */
3673  if (p == 1)
3674  appendPQExpBufferStr(&query, "minvalue");
3675  else
3676  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
3677 
3678  appendPQExpBufferStr(&query, ") to (");
3679 
3680  if (p < partitions)
3681  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
3682  else
3683  appendPQExpBufferStr(&query, "maxvalue");
3684 
3685  appendPQExpBufferChar(&query, ')');
3686  }
3687  else if (partition_method == PART_HASH)
3688  printfPQExpBuffer(&query,
3689  "create%s table pgbench_accounts_%d\n"
3690  " partition of pgbench_accounts\n"
3691  " for values with (modulus %d, remainder %d)",
3692  unlogged_tables ? " unlogged" : "", p,
3693  partitions, p - 1);
3694  else /* cannot get there */
3695  Assert(0);
3696 
3697  /*
3698  * Per ddlinfo in initCreateTables, fillfactor is needed on table
3699  * pgbench_accounts.
3700  */
3701  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
3702 
3703  executeStatement(con, query.data);
3704  }
3705 
3706  termPQExpBuffer(&query);
3707 }
static int partitions
Definition: pgbench.c:196
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
static partition_method_t partition_method
Definition: pgbench.c:206
int scale
Definition: pgbench.c:154
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int fillfactor
Definition: pgbench.c:160
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:380
#define naccounts
Definition: pgbench.c:219
#define Assert(condition)
Definition: c.h:792
#define INT64_FORMAT
Definition: c.h:471
bool unlogged_tables
Definition: pgbench.c:165
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3610 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3611 {
3612  int i;
3613 
3614  for (i = 0; i < length; i++)
3615  finishCon(&state[i]);
3616 }
static void finishCon(CState *st)
Definition: pgbench.c:6526
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1173 of file pgbench.c.

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

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

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

◆ doLog()

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

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

3485 {
3486  FILE *logfile = thread->logfile;
3487 
3488  Assert(use_log);
3489 
3490  /*
3491  * Skip the log entry if sampling is enabled and this row doesn't belong
3492  * to the random sample.
3493  */
3494  if (sample_rate != 0.0 &&
3496  return;
3497 
3498  /* should we aggregate the results or not? */
3499  if (agg_interval > 0)
3500  {
3501  /*
3502  * Loop until we reach the interval of the current moment, and print
3503  * any empty intervals in between (this may happen with very low tps,
3504  * e.g. --rate=0.1).
3505  */
3506  time_t now = time(NULL);
3507 
3508  while (agg->start_time + agg_interval <= now)
3509  {
3510  /* print aggregated report to logfile */
3511  fprintf(logfile, "%ld " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3512  (long) agg->start_time,
3513  agg->cnt,
3514  agg->latency.sum,
3515  agg->latency.sum2,
3516  agg->latency.min,
3517  agg->latency.max);
3518  if (throttle_delay)
3519  {
3520  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3521  agg->lag.sum,
3522  agg->lag.sum2,
3523  agg->lag.min,
3524  agg->lag.max);
3525  if (latency_limit)
3526  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3527  }
3528  fputc('\n', logfile);
3529 
3530  /* reset data and move to next interval */
3531  initStats(agg, agg->start_time + agg_interval);
3532  }
3533 
3534  /* accumulate the current transaction */
3535  accumStats(agg, skipped, latency, lag);
3536  }
3537  else
3538  {
3539  /* no, print raw transactions */
3540  struct timeval tv;
3541 
3542  gettimeofday(&tv, NULL);
3543  if (skipped)
3544  fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld",
3545  st->id, st->cnt, st->use_file,
3546  (long) tv.tv_sec, (long) tv.tv_usec);
3547  else
3548  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld",
3549  st->id, st->cnt, latency, st->use_file,
3550  (long) tv.tv_sec, (long) tv.tv_usec);
3551  if (throttle_delay)
3552  fprintf(logfile, " %.0f", lag);
3553  fputc('\n', logfile);
3554  }
3555 }
time_t start_time
Definition: pgbench.c:295
int gettimeofday(struct timeval *tp, struct timezone *tzp)
Definition: gettimeofday.c:104
double sample_rate
Definition: pgbench.c:170
int id
Definition: pgbench.c:402
SimpleStats lag
Definition: pgbench.c:300
static void initStats(StatsData *sd, time_t start_time)
Definition: pgbench.c:1108
double sum
Definition: pgbench.c:285
RandomState ts_sample_rs
Definition: pgbench.c:450
bool use_log
Definition: pgbench.c:230
static FILE * logfile
Definition: pg_regress.c:102
SimpleStats latency
Definition: pgbench.c:299
#define fprintf
Definition: port.h:219
double throttle_delay
Definition: pgbench.c:176
FILE * logfile
Definition: pgbench.c:453
int64 cnt
Definition: pgbench.c:296
int64 cnt
Definition: pgbench.c:429
int64 skipped
Definition: pgbench.c:297
double max
Definition: pgbench.c:284
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1121
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:792
double sum2
Definition: pgbench.c:286
unsigned short xseed[3]
Definition: pgbench.c:308
int64 latency_limit
Definition: pgbench.c:184
#define INT64_FORMAT
Definition: c.h:471
int use_file
Definition: pgbench.c:412
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542
double min
Definition: pgbench.c:283
int agg_interval
Definition: pgbench.c:232

◆ evalFunc()

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

Definition at line 2423 of file pgbench.c.

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

Referenced by evaluateExpr().

2425 {
2426  if (isLazyFunc(func))
2427  return evalLazyFunc(st, func, args, retval);
2428  else
2429  return evalStandardFunc(st, func, args, retval);
2430 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1764
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1881
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1757

◆ evalLazyFunc()

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

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

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

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

◆ evaluateExpr()

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

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

2440 {
2441  switch (expr->etype)
2442  {
2443  case ENODE_CONSTANT:
2444  {
2445  *retval = expr->u.constant;
2446  return true;
2447  }
2448 
2449  case ENODE_VARIABLE:
2450  {
2451  Variable *var;
2452 
2453  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2454  {
2455  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2456  return false;
2457  }
2458 
2459  if (!makeVariableValue(var))
2460  return false;
2461 
2462  *retval = var->value;
2463  return true;
2464  }
2465 
2466  case ENODE_FUNCTION:
2467  return evalFunc(st,
2468  expr->u.function.function,
2469  expr->u.function.args,
2470  retval);
2471 
2472  default:
2473  /* internal error which should never occur */
2474  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2475  exit(1);
2476  }
2477 }
PgBenchValue constant
Definition: pgbench.h:114
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1247
#define pg_log_error(...)
Definition: logging.h:80
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2423
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1307
PgBenchValue value
Definition: pgbench.c:268
union PgBenchExpr::@37 u
PgBenchFunction function
Definition: pgbench.h:121
struct PgBenchExpr::@37::@38 variable
PgBenchExprType etype
Definition: pgbench.h:111
#define pg_log_fatal(...)
Definition: logging.h:76

◆ evaluateSleep()

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

Definition at line 2856 of file pgbench.c.

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

Referenced by executeMetaCommand().

2857 {
2858  char *var;
2859  int usec;
2860 
2861  if (*argv[1] == ':')
2862  {
2863  if ((var = getVariable(st, argv[1] + 1)) == NULL)
2864  {
2865  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
2866  return false;
2867  }
2868  usec = atoi(var);
2869  }
2870  else
2871  usec = atoi(argv[1]);
2872 
2873  if (argc > 2)
2874  {
2875  if (pg_strcasecmp(argv[2], "ms") == 0)
2876  usec *= 1000;
2877  else if (pg_strcasecmp(argv[2], "s") == 0)
2878  usec *= 1000000;
2879  }
2880  else
2881  usec *= 1000000;
2882 
2883  *usecs = usec;
2884  return true;
2885 }
#define pg_log_error(...)
Definition: logging.h:80
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
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 3323 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().

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

◆ executeStatement()

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

Definition at line 1142 of file pgbench.c.

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

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

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

◆ findBuiltin()

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

Definition at line 4998 of file pgbench.c.

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

Referenced by main().

4999 {
5000  int i,
5001  found = 0,
5002  len = strlen(name);
5003  const BuiltinScript *result = NULL;
5004 
5005  for (i = 0; i < lengthof(builtin_script); i++)
5006  {
5007  if (strncmp(builtin_script[i].name, name, len) == 0)
5008  {
5009  result = &builtin_script[i];
5010  found++;
5011  }
5012  }
5013 
5014  /* ok, unambiguous result */
5015  if (found == 1)
5016  return result;
5017 
5018  /* error cases */
5019  if (found == 0)
5020  pg_log_fatal("no builtin script found for name \"%s\"", name);
5021  else /* found > 1 */
5022  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5023 
5025  exit(1);
5026 }
static void listAvailableScripts(void)
Definition: pgbench.c:4986
#define lengthof(array)
Definition: c.h:722
static const BuiltinScript builtin_script[]
Definition: pgbench.c:555
const char * name
Definition: encode.c:515
int i
#define pg_log_fatal(...)
Definition: logging.h:76

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6526 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6527 {
6528  if (st->con != NULL)
6529  {
6530  PQfinish(st->con);
6531  st->con = NULL;
6532  }
6533 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4120
PGconn * con
Definition: pgbench.c:401

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4477 of file pgbench.c.

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

Referenced by ParseScript().

4478 {
4479  termPQExpBuffer(&command->lines);
4480  if (command->first_line)
4481  pg_free(command->first_line);
4482  for (int i = 0; i < command->argc; i++)
4483  pg_free(command->argv[i]);
4484  if (command->varprefix)
4485  pg_free(command->varprefix);
4486 
4487  /*
4488  * It should also free expr recursively, but this is currently not needed
4489  * as only gset commands (which do not have an expression) are freed.
4490  */
4491  pg_free(command);
4492 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:529
PQExpBufferData lines
Definition: pgbench.c:524
int argc
Definition: pgbench.c:528
char * varprefix
Definition: pgbench.c:530
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:525

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 6700 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

6701 {
6702  pg_free(sa);
6703 }
void pg_free(void *ptr)
Definition: fe_memutils.c:105

◆ getExponentialRand()

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

Definition at line 870 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

◆ getGaussianRand()

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

Definition at line 894 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1020 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

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

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1045 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

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

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2483 of file pgbench.c.

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

Referenced by process_backslash_command().

2484 {
2485  MetaCommand mc;
2486 
2487  if (cmd == NULL)
2488  mc = META_NONE;
2489  else if (pg_strcasecmp(cmd, "set") == 0)
2490  mc = META_SET;
2491  else if (pg_strcasecmp(cmd, "setshell") == 0)
2492  mc = META_SETSHELL;
2493  else if (pg_strcasecmp(cmd, "shell") == 0)
2494  mc = META_SHELL;
2495  else if (pg_strcasecmp(cmd, "sleep") == 0)
2496  mc = META_SLEEP;
2497  else if (pg_strcasecmp(cmd, "if") == 0)
2498  mc = META_IF;
2499  else if (pg_strcasecmp(cmd, "elif") == 0)
2500  mc = META_ELIF;
2501  else if (pg_strcasecmp(cmd, "else") == 0)
2502  mc = META_ELSE;
2503  else if (pg_strcasecmp(cmd, "endif") == 0)
2504  mc = META_ENDIF;
2505  else if (pg_strcasecmp(cmd, "gset") == 0)
2506  mc = META_GSET;
2507  else if (pg_strcasecmp(cmd, "aset") == 0)
2508  mc = META_ASET;
2509  else
2510  mc = META_NONE;
2511  return mc;
2512 }
MetaCommand
Definition: pgbench.c:476
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ getPoissonRand()

static int64 getPoissonRand ( RandomState random_state,
double  center 
)
static

Definition at line 954 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

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

◆ getQueryParams()

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

Definition at line 1605 of file pgbench.c.

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

Referenced by sendCommand().

1606 {
1607  int i;
1608 
1609  for (i = 0; i < command->argc - 1; i++)
1610  params[i] = getVariable(st, command->argv[i + 1]);
1611 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1274
char * argv[MAX_ARGS]
Definition: pgbench.c:529
int argc
Definition: pgbench.c:528
int i

◆ getrand()

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

Definition at line 850 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), and evalStandardFunc().

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

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

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

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

◆ getVariable()

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

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

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

◆ getZipfianRand()

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

Definition at line 1006 of file pgbench.c.

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

Referenced by evalStandardFunc().

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

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6542 of file pgbench.c.

Referenced by setalarm().

6543 {
6544  timer_exceeded = true;
6545 }
volatile bool timer_exceeded
Definition: pgbench.c:252

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4065 of file pgbench.c.

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

Referenced by runInitSteps().

4066 {
4067  static const char *const DDLKEYs[] = {
4068  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4069  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4070  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4071  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4072  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4073  };
4074  int i;
4075 
4076  fprintf(stderr, "creating foreign keys...\n");
4077  for (i = 0; i < lengthof(DDLKEYs); i++)
4078  {
4079  executeStatement(con, DDLKEYs[i]);
4080  }
4081 }
#define lengthof(array)
Definition: c.h:722
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4027 of file pgbench.c.

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

Referenced by runInitSteps().

4028 {
4029  static const char *const DDLINDEXes[] = {
4030  "alter table pgbench_branches add primary key (bid)",
4031  "alter table pgbench_tellers add primary key (tid)",
4032  "alter table pgbench_accounts add primary key (aid)"
4033  };
4034  int i;
4035  PQExpBufferData query;
4036 
4037  fprintf(stderr, "creating primary keys...\n");
4038  initPQExpBuffer(&query);
4039 
4040  for (i = 0; i < lengthof(DDLINDEXes); i++)
4041  {
4042  resetPQExpBuffer(&query);
4043  appendPQExpBufferStr(&query, DDLINDEXes[i]);
4044 
4045  if (index_tablespace != NULL)
4046  {
4047  char *escape_tablespace;
4048 
4049  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4050  strlen(index_tablespace));
4051  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4052  PQfreemem(escape_tablespace);
4053  }
4054 
4055  executeStatement(con, query.data);
4056  }
4057 
4058  termPQExpBuffer(&query);
4059 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:369
#define lengthof(array)
Definition: c.h:722
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:3538
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * index_tablespace
Definition: pgbench.c:190
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
void PQfreemem(void *ptr)
Definition: fe-exec.c:3259
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 3713 of file pgbench.c.

References appendPQExpBuffer(), createPartitions(), PQExpBufferData::data, executeStatement(), fprintf, i, initPQExpBuffer(), lengthof, PART_NONE, PQescapeIdentifier(), PQfreemem(), printfPQExpBuffer(), SCALE_32BIT_THRESHOLD, and termPQExpBuffer().

Referenced by runInitSteps().

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

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3622 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3623 {
3624  fprintf(stderr, "dropping old tables...\n");
3625 
3626  /*
3627  * We drop all the tables in one command, so that whether there are
3628  * foreign key dependencies or not doesn't matter.
3629  */
3630  executeStatement(con, "drop table if exists "
3631  "pgbench_accounts, "
3632  "pgbench_branches, "
3633  "pgbench_history, "
3634  "pgbench_tellers");
3635 }
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 3821 of file pgbench.c.

References CancelRequested, PQExpBufferData::data, executeStatement(), fprintf, i, initPQExpBuffer(), 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(), printfPQExpBuffer(), scale, and termPQExpBuffer().

Referenced by runInitSteps().

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

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 3969 of file pgbench.c.

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

Referenced by runInitSteps().

3970 {
3971  PQExpBufferData sql;
3972 
3973  fprintf(stderr, "generating data (server-side)...\n");
3974 
3975  /*
3976  * we do all of this in one transaction to enable the backend's
3977  * data-loading optimizations
3978  */
3979  executeStatement(con, "begin");
3980 
3981  /* truncate away any old data */
3982  initTruncateTables(con);
3983 
3984  initPQExpBuffer(&sql);
3985 
3986  printfPQExpBuffer(&sql,
3987  "insert into pgbench_branches(bid,bbalance) "
3988  "select bid, 0 "
3989  "from generate_series(1, %d) as bid", nbranches * scale);
3990  executeStatement(con, sql.data);
3991 
3992  printfPQExpBuffer(&sql,
3993  "insert into pgbench_tellers(tid,bid,tbalance) "
3994  "select tid, (tid - 1) / %d + 1, 0 "
3995  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
3996  executeStatement(con, sql.data);
3997 
3998  printfPQExpBuffer(&sql,
3999  "insert into pgbench_accounts(aid,bid,abalance,filler) "
4000  "select aid, (aid - 1) / %d + 1, 0, '' "
4001  "from generate_series(1, " INT64_FORMAT ") as aid",
4002  naccounts, (int64) naccounts * scale);
4003  executeStatement(con, sql.data);
4004 
4005  termPQExpBuffer(&sql);
4006 
4007  executeStatement(con, "commit");
4008 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:154
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142
#define nbranches
Definition: pgbench.c:216
#define ntellers
Definition: pgbench.c:218
#define naccounts
Definition: pgbench.c:219
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:3808
#define INT64_FORMAT
Definition: c.h:471
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 831 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

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

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1068 of file pgbench.c.

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

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

◆ initStats()

static void initStats ( StatsData sd,
time_t  start_time 
)
static

Definition at line 1108 of file pgbench.c.

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

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

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

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 3808 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

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

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4014 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

4015 {
4016  fprintf(stderr, "vacuuming...\n");
4017  executeStatement(con, "vacuum analyze pgbench_branches");
4018  executeStatement(con, "vacuum analyze pgbench_tellers");
4019  executeStatement(con, "vacuum analyze pgbench_accounts");
4020  executeStatement(con, "vacuum analyze pgbench_history");
4021 }
#define fprintf
Definition: port.h:219
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1142

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 694 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

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

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1757 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1758 {
1759  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1760 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 4986 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

4987 {
4988  int i;
4989 
4990  fprintf(stderr, "Available builtin scripts:\n");
4991  for (i = 0; i < lengthof(builtin_script); i++)
4992  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
4993  fprintf(stderr, "\n");
4994 }
#define lengthof(array)
Definition: c.h:722
#define fprintf
Definition: port.h:219
static const BuiltinScript builtin_script[]
Definition: pgbench.c:555
const char * name
Definition: encode.c:515
int i

◆ lookupCreateVariable()

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

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

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

◆ lookupVariable()

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

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

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

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 5392 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_fatal, pg_log_info, pg_logging_increase_verbosity(), pg_logging_init(), 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.

5393 {
5394  static struct option long_options[] = {
5395  /* systematic long/short named options */
5396  {"builtin", required_argument, NULL, 'b'},
5397  {"client", required_argument, NULL, 'c'},
5398  {"connect", no_argument, NULL, 'C'},
5399  {"debug", no_argument, NULL, 'd'},
5400  {"define", required_argument, NULL, 'D'},
5401  {"file", required_argument, NULL, 'f'},
5402  {"fillfactor", required_argument, NULL, 'F'},
5403  {"host", required_argument, NULL, 'h'},
5404  {"initialize", no_argument, NULL, 'i'},
5405  {"init-steps", required_argument, NULL, 'I'},
5406  {"jobs", required_argument, NULL, 'j'},
5407  {"log", no_argument, NULL, 'l'},
5408  {"latency-limit", required_argument, NULL, 'L'},
5409  {"no-vacuum", no_argument, NULL, 'n'},
5410  {"port", required_argument, NULL, 'p'},
5411  {"progress", required_argument, NULL, 'P'},
5412  {"protocol", required_argument, NULL, 'M'},
5413  {"quiet", no_argument, NULL, 'q'},
5414  {"report-latencies", no_argument, NULL, 'r'},
5415  {"rate", required_argument, NULL, 'R'},
5416  {"scale", required_argument, NULL, 's'},
5417  {"select-only", no_argument, NULL, 'S'},
5418  {"skip-some-updates", no_argument, NULL, 'N'},
5419  {"time", required_argument, NULL, 'T'},
5420  {"transactions", required_argument, NULL, 't'},
5421  {"username", required_argument, NULL, 'U'},
5422  {"vacuum-all", no_argument, NULL, 'v'},
5423  /* long-named only options */
5424  {"unlogged-tables", no_argument, NULL, 1},
5425  {"tablespace", required_argument, NULL, 2},
5426  {"index-tablespace", required_argument, NULL, 3},
5427  {"sampling-rate", required_argument, NULL, 4},
5428  {"aggregate-interval", required_argument, NULL, 5},
5429  {"progress-timestamp", no_argument, NULL, 6},
5430  {"log-prefix", required_argument, NULL, 7},
5431  {"foreign-keys", no_argument, NULL, 8},
5432  {"random-seed", required_argument, NULL, 9},
5433  {"show-script", required_argument, NULL, 10},
5434  {"partitions", required_argument, NULL, 11},
5435  {"partition-method", required_argument, NULL, 12},
5436  {NULL, 0, NULL, 0}
5437  };
5438 
5439  int c;
5440  bool is_init_mode = false; /* initialize mode? */
5441  char *initialize_steps = NULL;
5442  bool foreign_keys = false;
5443  bool is_no_vacuum = false;
5444  bool do_vacuum_accounts = false; /* vacuum accounts table? */
5445  int optindex;
5446  bool scale_given = false;
5447 
5448  bool benchmarking_option_set = false;
5449  bool initialization_option_set = false;
5450  bool internal_script_used = false;
5451 
5452  CState *state; /* status of clients */
5453  TState *threads; /* array of thread */
5454 
5455  instr_time start_time; /* start up time */
5456  instr_time total_time;
5457  instr_time conn_total_time;
5458  int64 latency_late = 0;
5459  StatsData stats;
5460  int weight;
5461 
5462  int i;
5463  int nclients_dealt;
5464 
5465 #ifdef HAVE_GETRLIMIT
5466  struct rlimit rlim;
5467 #endif
5468 
5469  PGconn *con;
5470  char *env;
5471 
5472  int exit_code = 0;
5473 
5474  pg_logging_init(argv[0]);
5475  progname = get_progname(argv[0]);
5476 
5477  if (argc > 1)
5478  {
5479  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
5480  {
5481  usage();
5482  exit(0);
5483  }
5484  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
5485  {
5486  puts("pgbench (PostgreSQL) " PG_VERSION);
5487  exit(0);
5488  }
5489  }
5490 
5491  if ((env = getenv("PGHOST")) != NULL && *env != '\0')
5492  pghost = env;
5493  if ((env = getenv("PGPORT")) != NULL && *env != '\0')
5494  pgport = env;
5495  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
5496  login = env;
5497 
5498  state = (CState *) pg_malloc0(sizeof(CState));
5499 
5500  /* set random seed early, because it may be used while parsing scripts. */
5501  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
5502  {
5503  pg_log_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
5504  exit(1);
5505  }
5506 
5507  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)
5508  {
5509  char *script;
5510 
5511  switch (c)
5512  {
5513  case 'i':
5514  is_init_mode = true;
5515  break;
5516  case 'I':
5517  if (initialize_steps)
5518  pg_free(initialize_steps);
5519  initialize_steps = pg_strdup(optarg);
5520  checkInitSteps(initialize_steps);
5521  initialization_option_set = true;
5522  break;
5523  case 'h':
5524  pghost = pg_strdup(optarg);
5525  break;
5526  case 'n':
5527  is_no_vacuum = true;
5528  break;
5529  case 'v':
5530  benchmarking_option_set = true;
5531  do_vacuum_accounts = true;
5532  break;
5533  case 'p':
5534  pgport = pg_strdup(optarg);
5535  break;
5536  case 'd':