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 "common/username.h"
#include "fe_utils/cancel.h"
#include "fe_utils/conditional.h"
#include "fe_utils/option_utils.h"
#include "fe_utils/string_utils.h"
#include "getopt_long.h"
#include "libpq-fe.h"
#include "pgbench.h"
#include "port/pg_bitutils.h"
#include "portability/instr_time.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

struct  socket_set
 
struct  Variable
 
struct  SimpleStats
 
struct  StatsData
 
struct  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 THREAD_T   void *
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_BARRIER_T   int
 
#define THREAD_BARRIER_INIT(barrier, n)   (*(barrier) = 0)
 
#define THREAD_BARRIER_WAIT(barrier)
 
#define THREAD_BARRIER_DESTROY(barrier)
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#define PG_TIME_GET_DOUBLE(t)   (0.000001 * (t))
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define MAX_PREPARE_NAME   32
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef 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, META_STARTPIPELINE,
  META_ENDPIPELINE
}
 
enum  QueryMode { QUERY_SIMPLE, QUERY_EXTENDED, QUERY_PREPARED, NUM_QUERYMODE }
 

Functions

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

Variables

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

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

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

Referenced by main(), and usage().

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 176 of file pgbench.c.

Referenced by main().

◆ ERRCODE_UNDEFINED_TABLE

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 84 of file pgbench.c.

Referenced by getHashFnv1a().

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 83 of file pgbench.c.

Referenced by getHashFnv1a().

◆ LOG_STEP_SECONDS

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

Definition at line 175 of file pgbench.c.

Referenced by initGenerateDataClientSide().

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 75 of file pgbench.c.

Referenced by evalStandardFunc(), and getGaussianRand().

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 529 of file pgbench.c.

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

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2055 of file pgbench.c.

Referenced by evalStandardFunc().

◆ MAX_PREPARE_NAME

#define MAX_PREPARE_NAME   32

Definition at line 2829 of file pgbench.c.

Referenced by sendCommand().

◆ MAX_SCRIPTS

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

Definition at line 308 of file pgbench.c.

Referenced by addScript().

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 181 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 178 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 180 of file pgbench.c.

Referenced by evalStandardFunc(), and getZipfianRand().

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 85 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 86 of file pgbench.c.

Referenced by getHashMurmur2().

◆ MM2_ROT

#define MM2_ROT   47

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

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ ntellers

#define ntellers   10

Definition at line 255 of file pgbench.c.

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

Referenced by doConnect().

◆ PG_TIME_GET_DOUBLE

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

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 54 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 265 of file pgbench.c.

Referenced by initCreateTables().

◆ SHELL_COMMAND_SIZE

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

Definition at line 309 of file pgbench.c.

Referenced by runShellCommand().

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 106 of file pgbench.c.

Referenced by threadRun().

◆ SQL_COMMAND

#define SQL_COMMAND   1

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)

Definition at line 165 of file pgbench.c.

Referenced by main().

◆ THREAD_BARRIER_INIT

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

Definition at line 163 of file pgbench.c.

Referenced by main().

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   int

Definition at line 162 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)

Definition at line 164 of file pgbench.c.

Referenced by threadRun().

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 161 of file pgbench.c.

Referenced by main().

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 160 of file pgbench.c.

Referenced by threadRun().

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 159 of file pgbench.c.

Referenced by main().

◆ THREAD_T

#define THREAD_T   void *

Definition at line 158 of file pgbench.c.

◆ WSEP

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

Definition at line 287 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

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 331 of file pgbench.c.

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

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

◆ MetaCommand

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

Definition at line 531 of file pgbench.c.

532 {
533  META_NONE, /* not a known meta-command */
534  META_SET, /* \set */
535  META_SETSHELL, /* \setshell */
536  META_SHELL, /* \shell */
537  META_SLEEP, /* \sleep */
538  META_GSET, /* \gset */
539  META_ASET, /* \aset */
540  META_IF, /* \if */
541  META_ELIF, /* \elif */
542  META_ELSE, /* \else */
543  META_ENDIF, /* \endif */
544  META_STARTPIPELINE, /* \startpipeline */
545  META_ENDPIPELINE /* \endpipeline */
546 } MetaCommand;
MetaCommand
Definition: pgbench.c:531

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 236 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 548 of file pgbench.c.

549 {
550  QUERY_SIMPLE, /* simple query */
551  QUERY_EXTENDED, /* extended query */
552  QUERY_PREPARED, /* extended query with prepared statements */
554 } QueryMode;
QueryMode
Definition: pgbench.c:548

Function Documentation

◆ accumStats()

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

Definition at line 1303 of file pgbench.c.

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

Referenced by doLog(), and processXactStats().

1304 {
1305  stats->cnt++;
1306 
1307  if (skipped)
1308  {
1309  /* no latency to record on skipped transactions */
1310  stats->skipped++;
1311  }
1312  else
1313  {
1314  addToSimpleStats(&stats->latency, lat);
1315 
1316  /* and possibly the same for schedule lag */
1317  if (throttle_delay)
1318  addToSimpleStats(&stats->lag, lag);
1319  }
1320 }
SimpleStats lag
Definition: pgbench.c:344
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1259
SimpleStats latency
Definition: pgbench.c:343
double throttle_delay
Definition: pgbench.c:213
int64 cnt
Definition: pgbench.c:340
int64 skipped
Definition: pgbench.c:341

◆ add_socket_to_set()

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

Definition at line 7069 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

7070 {
7071  if (fd < 0 || fd >= FD_SETSIZE)
7072  {
7073  /*
7074  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7075  * complicating the API to make it less grotty.
7076  */
7077  pg_log_fatal("too many client connections for select()");
7078  exit(1);
7079  }
7080  FD_SET(fd, &sa->fds);
7081  if (fd > sa->maxfd)
7082  sa->maxfd = fd;
7083 }
static int fd(const char *x, int i)
Definition: preproc-init.c:105
fd_set fds
Definition: pgbench.c:111
int maxfd
Definition: pgbench.c:110
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addScript()

static void addScript ( ParsedScript  script)
static

Definition at line 5430 of file pgbench.c.

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

Referenced by ParseScript().

5431 {
5432  if (script.commands == NULL || script.commands[0] == NULL)
5433  {
5434  pg_log_fatal("empty command list for script \"%s\"", script.desc);
5435  exit(1);
5436  }
5437 
5438  if (num_scripts >= MAX_SCRIPTS)
5439  {
5440  pg_log_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
5441  exit(1);
5442  }
5443 
5444  CheckConditional(script);
5445 
5446  sql_script[num_scripts] = script;
5447  num_scripts++;
5448 }
static int num_scripts
Definition: pgbench.c:601
#define MAX_SCRIPTS
Definition: pgbench.c:308
static void CheckConditional(ParsedScript ps)
Definition: pgbench.c:5080
const char * desc
Definition: pgbench.c:594
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:600
Command ** commands
Definition: pgbench.c:596
#define pg_log_fatal(...)
Definition: logging.h:76

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1259 of file pgbench.c.

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

Referenced by accumStats(), and advanceConnectionState().

1260 {
1261  if (ss->count == 0 || val < ss->min)
1262  ss->min = val;
1263  if (ss->count == 0 || val > ss->max)
1264  ss->max = val;
1265  ss->count++;
1266  ss->sum += val;
1267  ss->sum2 += val * val;
1268 }
double sum
Definition: pgbench.c:322
int64 count
Definition: pgbench.c:319
double max
Definition: pgbench.c:321
double sum2
Definition: pgbench.c:323
long val
Definition: informix.c:664
double min
Definition: pgbench.c:320

◆ advanceConnectionState()

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

Definition at line 3129 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_duration, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, ParsedScript::desc, doConnect(), duration, end_time, executeMetaCommand(), finishCon(), getPoissonRand(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, is_connect, latency_limit, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, now(), nxacts, pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQconsumeInput(), PQisBusy(), PQpipelineStatus(), CState::prepared, processXactStats(), readCommandResponse(), report_per_command, sendCommand(), SQL_COMMAND, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, TState::ts_throttle_rs, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, and Command::varprefix.

Referenced by threadRun().

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

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7050 of file pgbench.c.

References pg_malloc0().

Referenced by setalarm(), and threadRun().

7051 {
7052  return (socket_set *) pg_malloc0(sizeof(socket_set));
7053 }
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

◆ assignVariables()

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

Definition at line 1750 of file pgbench.c.

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

Referenced by sendCommand().

1751 {
1752  char *p,
1753  *name,
1754  *val;
1755 
1756  p = sql;
1757  while ((p = strchr(p, ':')) != NULL)
1758  {
1759  int eaten;
1760 
1761  name = parseVariable(p, &eaten);
1762  if (name == NULL)
1763  {
1764  while (*p == ':')
1765  {
1766  p++;
1767  }
1768  continue;
1769  }
1770 
1771  val = getVariable(st, name);
1772  free(name);
1773  if (val == NULL)
1774  {
1775  p++;
1776  continue;
1777  }
1778 
1779  p = replaceVariable(&sql, p, eaten, val);
1780  }
1781 
1782  return sql;
1783 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1455
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1730
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1703
const char * name
Definition: encode.c:561
long val
Definition: informix.c:664

◆ CheckConditional()

static void CheckConditional ( ParsedScript  ps)
static

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

5081 {
5082  /* statically check conditional structure */
5084  int i;
5085 
5086  for (i = 0; ps.commands[i] != NULL; i++)
5087  {
5088  Command *cmd = ps.commands[i];
5089 
5090  if (cmd->type == META_COMMAND)
5091  {
5092  switch (cmd->meta)
5093  {
5094  case META_IF:
5096  break;
5097  case META_ELIF:
5098  if (conditional_stack_empty(cs))
5099  ConditionError(ps.desc, i + 1, "\\elif without matching \\if");
5101  ConditionError(ps.desc, i + 1, "\\elif after \\else");
5102  break;
5103  case META_ELSE:
5104  if (conditional_stack_empty(cs))
5105  ConditionError(ps.desc, i + 1, "\\else without matching \\if");
5107  ConditionError(ps.desc, i + 1, "\\else after \\else");
5109  break;
5110  case META_ENDIF:
5111  if (!conditional_stack_pop(cs))
5112  ConditionError(ps.desc, i + 1, "\\endif without matching \\if");
5113  break;
5114  default:
5115  /* ignore anything else... */
5116  break;
5117  }
5118  }
5119  }
5120  if (!conditional_stack_empty(cs))
5121  ConditionError(ps.desc, i + 1, "\\if without matching \\endif");
5123 }
int type
Definition: pgbench.c:583
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:57
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5069
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:41
#define META_COMMAND
Definition: pgbench.c:523
const char * desc
Definition: pgbench.c:594
MetaCommand meta
Definition: pgbench.c:584
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:596
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 4425 of file pgbench.c.

References ALL_INIT_STEPS, pg_log_fatal, and pg_log_info.

Referenced by main().

4426 {
4427  if (initialize_steps[0] == '\0')
4428  {
4429  pg_log_fatal("no initialization steps specified");
4430  exit(1);
4431  }
4432 
4433  for (const char *step = initialize_steps; *step != '\0'; step++)
4434  {
4435  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
4436  {
4437  pg_log_fatal("unrecognized initialization step \"%c\"", *step);
4438  pg_log_info("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
4439  exit(1);
4440  }
4441  }
4442 }
#define ALL_INIT_STEPS
Definition: pgbench.c:173
#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 2845 of file pgbench.c.

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

Referenced by advanceConnectionState().

2846 {
2847  int i = 0;
2848  int64 w;
2849 
2850  if (num_scripts == 1)
2851  return 0;
2852 
2853  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
2854  do
2855  {
2856  w -= sql_script[i++].weight;
2857  } while (w >= 0);
2858 
2859  return i - 1;
2860 }
static int num_scripts
Definition: pgbench.c:601
static int64 getrand(RandomState *random_state, int64 min, int64 max)
Definition: pgbench.c:925
int weight
Definition: pgbench.c:595
RandomState ts_choose_rs
Definition: pgbench.c:501
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:600
static int64 total_weight
Definition: pgbench.c:602
int i

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 7062 of file pgbench.c.

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

Referenced by setalarm(), and threadRun().

7063 {
7064  FD_ZERO(&sa->fds);
7065  sa->maxfd = -1;
7066 }
fd_set fds
Definition: pgbench.c:111
int maxfd
Definition: pgbench.c:110

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1817 of file pgbench.c.

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

Referenced by evalLazyFunc(), and evalStandardFunc().

1818 {
1819  if (pval->type == PGBT_BOOLEAN)
1820  {
1821  *bval = pval->u.bval;
1822  return true;
1823  }
1824  else /* NULL, INT or DOUBLE */
1825  {
1826  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
1827  *bval = false; /* suppress uninitialized-variable warnings */
1828  return false;
1829  }
1830 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1795
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46

◆ coerceToDouble()

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

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

1887 {
1888  if (pval->type == PGBT_DOUBLE)
1889  {
1890  *dval = pval->u.dval;
1891  return true;
1892  }
1893  else if (pval->type == PGBT_INT)
1894  {
1895  *dval = (double) pval->u.ival;
1896  return true;
1897  }
1898  else /* BOOLEAN or NULL */
1899  {
1900  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
1901  return false;
1902  }
1903 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1795
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ coerceToInt()

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

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

1859 {
1860  if (pval->type == PGBT_INT)
1861  {
1862  *ival = pval->u.ival;
1863  return true;
1864  }
1865  else if (pval->type == PGBT_DOUBLE)
1866  {
1867  double dval = rint(pval->u.dval);
1868 
1869  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
1870  {
1871  pg_log_error("double to int overflow for %f", dval);
1872  return false;
1873  }
1874  *ival = (int64) dval;
1875  return true;
1876  }
1877  else /* BOOLEAN or NULL */
1878  {
1879  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
1880  return false;
1881  }
1882 }
#define pg_log_error(...)
Definition: logging.h:80
union PgBenchValue::@31 u
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1107
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1795
double dval
Definition: pgbench.h:50
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49

◆ commandFailed()

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

Definition at line 2837 of file pgbench.c.

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

Referenced by advanceConnectionState(), and executeMetaCommand().

2838 {
2839  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
2840  st->id, st->command, cmd, st->use_file, message);
2841 }
int id
Definition: pgbench.c:456
#define pg_log_error(...)
Definition: logging.h:80
int command
Definition: pgbench.c:467
int use_file
Definition: pgbench.c:466

◆ compareVariableNames()

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

Definition at line 1420 of file pgbench.c.

References name.

Referenced by lookupVariable().

1421 {
1422  return strcmp(((const Variable *) v1)->name,
1423  ((const Variable *) v2)->name);
1424 }
const char * name
Definition: encode.c:561

◆ computeIterativeZipfian()

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

Definition at line 1051 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by getZipfianRand().

1052 {
1053  double b = pow(2.0, s - 1.0);
1054  double x,
1055  t,
1056  u,
1057  v;
1058 
1059  /* Ensure n is sane */
1060  if (n <= 1)
1061  return 1;
1062 
1063  while (true)
1064  {
1065  /* random variates */
1066  u = pg_erand48(random_state->xseed);
1067  v = pg_erand48(random_state->xseed);
1068 
1069  x = floor(pow(u, -1.0 / (s - 1.0)));
1070 
1071  t = pow(1.0 + 1.0 / x, s - 1.0);
1072  /* reject if too large or out of bound */
1073  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1074  break;
1075  }
1076  return (int64) x;
1077 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:358

◆ ConditionError()

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

Definition at line 5069 of file pgbench.c.

References pg_log_fatal.

Referenced by CheckConditional().

5070 {
5071  pg_log_fatal("condition error in script \"%s\" command %d: %s",
5072  desc, cmdn, msg);
5073  exit(1);
5074 }
#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 4778 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().

4779 {
4780  Command *my_command;
4781  char *p = skip_sql_comments(buf->data);
4782 
4783  if (p == NULL)
4784  return NULL;
4785 
4786  /* Allocate and initialize Command structure */
4787  my_command = (Command *) pg_malloc(sizeof(Command));
4788  initPQExpBuffer(&my_command->lines);
4789  appendPQExpBufferStr(&my_command->lines, p);
4790  my_command->first_line = NULL; /* this is set later */
4791  my_command->type = SQL_COMMAND;
4792  my_command->meta = META_NONE;
4793  my_command->argc = 0;
4794  memset(my_command->argv, 0, sizeof(my_command->argv));
4795  my_command->varprefix = NULL; /* allocated later, if needed */
4796  my_command->expr = NULL;
4797  initSimpleStats(&my_command->stats);
4798 
4799  return my_command;
4800 }
int type
Definition: pgbench.c:583
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:588
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:4743
char * argv[MAX_ARGS]
Definition: pgbench.c:586
MetaCommand meta
Definition: pgbench.c:584
PQExpBufferData lines
Definition: pgbench.c:581
int argc
Definition: pgbench.c:585
#define SQL_COMMAND
Definition: pgbench.c:522
SimpleStats stats
Definition: pgbench.c:589
char * varprefix
Definition: pgbench.c:587
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1250
char * first_line
Definition: pgbench.c:582
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 3978 of file pgbench.c.

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

Referenced by initCreateTables().

3979 {
3980  PQExpBufferData query;
3981 
3982  /* we must have to create some partitions */
3983  Assert(partitions > 0);
3984 
3985  fprintf(stderr, "creating %d partitions...\n", partitions);
3986 
3987  initPQExpBuffer(&query);
3988 
3989  for (int p = 1; p <= partitions; p++)
3990  {
3992  {
3993  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
3994 
3995  printfPQExpBuffer(&query,
3996  "create%s table pgbench_accounts_%d\n"
3997  " partition of pgbench_accounts\n"
3998  " for values from (",
3999  unlogged_tables ? " unlogged" : "", p);
4000 
4001  /*
4002  * For RANGE, we use open-ended partitions at the beginning and
4003  * end to allow any valid value for the primary key. Although the
4004  * actual minimum and maximum values can be derived from the
4005  * scale, it is more generic and the performance is better.
4006  */
4007  if (p == 1)
4008  appendPQExpBufferStr(&query, "minvalue");
4009  else
4010  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4011 
4012  appendPQExpBufferStr(&query, ") to (");
4013 
4014  if (p < partitions)
4015  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4016  else
4017  appendPQExpBufferStr(&query, "maxvalue");
4018 
4019  appendPQExpBufferChar(&query, ')');
4020  }
4021  else if (partition_method == PART_HASH)
4022  printfPQExpBuffer(&query,
4023  "create%s table pgbench_accounts_%d\n"
4024  " partition of pgbench_accounts\n"
4025  " for values with (modulus %d, remainder %d)",
4026  unlogged_tables ? " unlogged" : "", p,
4027  partitions, p - 1);
4028  else /* cannot get there */
4029  Assert(0);
4030 
4031  /*
4032  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4033  * pgbench_accounts.
4034  */
4035  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4036 
4037  executeStatement(con, query.data);
4038  }
4039 
4040  termPQExpBuffer(&query);
4041 }
static int partitions
Definition: pgbench.c:233
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:243
int scale
Definition: pgbench.c:191
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
int fillfactor
Definition: pgbench.c:197
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:256
#define Assert(condition)
Definition: c.h:804
#define INT64_FORMAT
Definition: c.h:483
bool unlogged_tables
Definition: pgbench.c:202
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 3944 of file pgbench.c.

References finishCon(), and i.

Referenced by main(), and threadRun().

3945 {
3946  int i;
3947 
3948  for (i = 0; i < length; i++)
3949  finishCon(&state[i]);
3950 }
static void finishCon(CState *st)
Definition: pgbench.c:6882
int i

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1355 of file pgbench.c.

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

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

1356 {
1357  PGconn *conn;
1358  bool new_pass;
1359  static char *password = NULL;
1360 
1361  /*
1362  * Start the connection. Loop until we have a password if requested by
1363  * backend.
1364  */
1365  do
1366  {
1367 #define PARAMS_ARRAY_SIZE 7
1368 
1369  const char *keywords[PARAMS_ARRAY_SIZE];
1370  const char *values[PARAMS_ARRAY_SIZE];
1371 
1372  keywords[0] = "host";
1373  values[0] = pghost;
1374  keywords[1] = "port";
1375  values[1] = pgport;
1376  keywords[2] = "user";
1377  values[2] = username;
1378  keywords[3] = "password";
1379  values[3] = password;
1380  keywords[4] = "dbname";
1381  values[4] = dbName;
1382  keywords[5] = "fallback_application_name";
1383  values[5] = progname;
1384  keywords[6] = NULL;
1385  values[6] = NULL;
1386 
1387  new_pass = false;
1388 
1389  conn = PQconnectdbParams(keywords, values, true);
1390 
1391  if (!conn)
1392  {
1393  pg_log_error("connection to database \"%s\" failed", dbName);
1394  return NULL;
1395  }
1396 
1397  if (PQstatus(conn) == CONNECTION_BAD &&
1398  PQconnectionNeedsPassword(conn) &&
1399  !password)
1400  {
1401  PQfinish(conn);
1402  password = simple_prompt("Password: ", false);
1403  new_pass = true;
1404  }
1405  } while (new_pass);
1406 
1407  /* check to see that the backend connection was successfully made */
1408  if (PQstatus(conn) == CONNECTION_BAD)
1409  {
1410  pg_log_error("%s", PQerrorMessage(conn));
1411  PQfinish(conn);
1412  return NULL;
1413  }
1414 
1415  return conn;
1416 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6744
#define pg_log_error(...)
Definition: logging.h:80
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4231
const char * pghost
Definition: pgbench.c:280
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
const char * dbName
Definition: pgbench.c:283
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:657
PGconn * conn
Definition: streamutil.c:54
static char * password
Definition: streamutil.c:53
#define PARAMS_ARRAY_SIZE
const char * username
Definition: pgbench.c:282
const char * progname
Definition: pgbench.c:285
static Datum values[MAXATTR]
Definition: bootstrap.c:156
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:6795
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:6691
const char * pgport
Definition: pgbench.c:281

◆ doLog()

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

Definition at line 3817 of file pgbench.c.

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

Referenced by processXactStats(), and threadRun().

3819 {
3820  FILE *logfile = thread->logfile;
3822 
3823  Assert(use_log);
3824 
3825  /*
3826  * Skip the log entry if sampling is enabled and this row doesn't belong
3827  * to the random sample.
3828  */
3829  if (sample_rate != 0.0 &&
3831  return;
3832 
3833  /* should we aggregate the results or not? */
3834  if (agg_interval > 0)
3835  {
3837 
3838  /*
3839  * Loop until we reach the interval of the current moment, and print
3840  * any empty intervals in between (this may happen with very low tps,
3841  * e.g. --rate=0.1).
3842  */
3843 
3844  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
3845  {
3846  /* print aggregated report to logfile */
3847  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
3848  agg->start_time / 1000000, /* seconds since Unix epoch */
3849  agg->cnt,
3850  agg->latency.sum,
3851  agg->latency.sum2,
3852  agg->latency.min,
3853  agg->latency.max);
3854  if (throttle_delay)
3855  {
3856  fprintf(logfile, " %.0f %.0f %.0f %.0f",
3857  agg->lag.sum,
3858  agg->lag.sum2,
3859  agg->lag.min,
3860  agg->lag.max);
3861  if (latency_limit)
3862  fprintf(logfile, " " INT64_FORMAT, agg->skipped);
3863  }
3864  fputc('\n', logfile);
3865 
3866  /* reset data and move to next interval */
3867  initStats(agg, next);
3868  }
3869 
3870  /* accumulate the current transaction */
3871  accumStats(agg, skipped, latency, lag);
3872  }
3873  else
3874  {
3875  /* no, print raw transactions */
3876  if (skipped)
3877  fprintf(logfile, "%d " INT64_FORMAT " skipped %d " INT64_FORMAT " "
3878  INT64_FORMAT,
3879  st->id, st->cnt, st->use_file, now / 1000000, now % 1000000);
3880  else
3881  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
3882  INT64_FORMAT,
3883  st->id, st->cnt, latency, st->use_file,
3884  now / 1000000, now % 1000000);
3885  if (throttle_delay)
3886  fprintf(logfile, " %.0f", lag);
3887  fputc('\n', logfile);
3888  }
3889 }
pg_time_usec_t start_time
Definition: pgbench.c:339
double sample_rate
Definition: pgbench.c:207
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:681
static int32 next
Definition: blutils.c:219
int id
Definition: pgbench.c:456
int64 pg_time_usec_t
Definition: pgbench.c:331
SimpleStats lag
Definition: pgbench.c:344
double sum
Definition: pgbench.c:322
RandomState ts_sample_rs
Definition: pgbench.c:503
bool use_log
Definition: pgbench.c:267
static FILE * logfile
Definition: pg_regress.c:102
SimpleStats latency
Definition: pgbench.c:343
#define fprintf
Definition: port.h:220
double throttle_delay
Definition: pgbench.c:213
FILE * logfile
Definition: pgbench.c:506
int64 cnt
Definition: pgbench.c:340
pg_time_usec_t epoch_shift
Definition: pgbench.c:351
int64 cnt
Definition: pgbench.c:483
int64 skipped
Definition: pgbench.c:341
double max
Definition: pgbench.c:321
static void accumStats(StatsData *stats, bool skipped, double lat, double lag)
Definition: pgbench.c:1303
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1290
#define Assert(condition)
Definition: c.h:804
double sum2
Definition: pgbench.c:323
unsigned short xseed[3]
Definition: pgbench.c:358
int64 latency_limit
Definition: pgbench.c:221
#define INT64_FORMAT
Definition: c.h:483
int use_file
Definition: pgbench.c:466
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
double min
Definition: pgbench.c:320
int agg_interval
Definition: pgbench.c:269

◆ evalFunc()

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

Definition at line 2629 of file pgbench.c.

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

Referenced by evaluateExpr().

2631 {
2632  if (isLazyFunc(func))
2633  return evalLazyFunc(st, func, args, retval);
2634  else
2635  return evalStandardFunc(st, func, args, retval);
2636 }
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1945
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2062
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1938

◆ evalLazyFunc()

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

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

1947 {
1948  PgBenchValue a1,
1949  a2;
1950  bool ba1,
1951  ba2;
1952 
1953  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
1954 
1955  /* args points to first condition */
1956  if (!evaluateExpr(st, args->expr, &a1))
1957  return false;
1958 
1959  /* second condition for AND/OR and corresponding branch for CASE */
1960  args = args->next;
1961 
1962  switch (func)
1963  {
1964  case PGBENCH_AND:
1965  if (a1.type == PGBT_NULL)
1966  {
1967  setNullValue(retval);
1968  return true;
1969  }
1970 
1971  if (!coerceToBool(&a1, &ba1))
1972  return false;
1973 
1974  if (!ba1)
1975  {
1976  setBoolValue(retval, false);
1977  return true;
1978  }
1979 
1980  if (!evaluateExpr(st, args->expr, &a2))
1981  return false;
1982 
1983  if (a2.type == PGBT_NULL)
1984  {
1985  setNullValue(retval);
1986  return true;
1987  }
1988  else if (!coerceToBool(&a2, &ba2))
1989  return false;
1990  else
1991  {
1992  setBoolValue(retval, ba2);
1993  return true;
1994  }
1995 
1996  return true;
1997 
1998  case PGBENCH_OR:
1999 
2000  if (a1.type == PGBT_NULL)
2001  {
2002  setNullValue(retval);
2003  return true;
2004  }
2005 
2006  if (!coerceToBool(&a1, &ba1))
2007  return false;
2008 
2009  if (ba1)
2010  {
2011  setBoolValue(retval, true);
2012  return true;
2013  }
2014 
2015  if (!evaluateExpr(st, args->expr, &a2))
2016  return false;
2017 
2018  if (a2.type == PGBT_NULL)
2019  {
2020  setNullValue(retval);
2021  return true;
2022  }
2023  else if (!coerceToBool(&a2, &ba2))
2024  return false;
2025  else
2026  {
2027  setBoolValue(retval, ba2);
2028  return true;
2029  }
2030 
2031  case PGBENCH_CASE:
2032  /* when true, execute branch */
2033  if (valueTruth(&a1))
2034  return evaluateExpr(st, args->expr, retval);
2035 
2036  /* now args contains next condition or final else expression */
2037  args = args->next;
2038 
2039  /* final else case? */
2040  if (args->next == NULL)
2041  return evaluateExpr(st, args->expr, retval);
2042 
2043  /* no, another when, proceed */
2044  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2045 
2046  default:
2047  /* internal error, cannot get here */
2048  Assert(0);
2049  break;
2050  }
2051  return false;
2052 }
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:1817
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:1945
static const FormData_pg_attribute a2
Definition: heap.c:167
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2645
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:1915
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:1907
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:1938
#define Assert(condition)
Definition: c.h:804
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1837
PgBenchValueType type
Definition: pgbench.h:46
static const FormData_pg_attribute a1
Definition: heap.c:153

◆ evalStandardFunc()

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

Definition at line 2062 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, permute(), pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PERMUTE, PGBENCH_PI, PGBENCH_POW, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_ZIPFIAN, PGBENCH_RSHIFT, PGBENCH_SQRT, PGBENCH_SUB, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), PgBenchValue::type, generate_unaccent_rules::type, PgBenchValue::u, unlikely, CState::use_file, and val.

Referenced by evalFunc().

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

◆ evaluateExpr()

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

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

2646 {
2647  switch (expr->etype)
2648  {
2649  case ENODE_CONSTANT:
2650  {
2651  *retval = expr->u.constant;
2652  return true;
2653  }
2654 
2655  case ENODE_VARIABLE:
2656  {
2657  Variable *var;
2658 
2659  if ((var = lookupVariable(st, expr->u.variable.varname)) == NULL)
2660  {
2661  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2662  return false;
2663  }
2664 
2665  if (!makeVariableValue(var))
2666  return false;
2667 
2668  *retval = var->value;
2669  return true;
2670  }
2671 
2672  case ENODE_FUNCTION:
2673  return evalFunc(st,
2674  expr->u.function.function,
2675  expr->u.function.args,
2676  retval);
2677 
2678  default:
2679  /* internal error which should never occur */
2680  pg_log_fatal("unexpected enode type in evaluation: %d", expr->etype);
2681  exit(1);
2682  }
2683 }
PgBenchValue constant
Definition: pgbench.h:115
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1428
#define pg_log_error(...)
Definition: logging.h:80
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2629
struct PgBenchExpr::@32::@33 variable
union PgBenchExpr::@32 u
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1488
PgBenchValue value
Definition: pgbench.c:305
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
#define pg_log_fatal(...)
Definition: logging.h:76

◆ evaluateSleep()

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

Definition at line 3085 of file pgbench.c.

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

Referenced by executeMetaCommand().

3086 {
3087  char *var;
3088  int usec;
3089 
3090  if (*argv[1] == ':')
3091  {
3092  if ((var = getVariable(st, argv[1] + 1)) == NULL)
3093  {
3094  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3095  return false;
3096  }
3097 
3098  usec = atoi(var);
3099 
3100  /* Raise an error if the value of a variable is not a number */
3101  if (usec == 0 && !isdigit((unsigned char) *var))
3102  {
3103  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3104  argv[0], var, argv[1] + 1);
3105  return false;
3106  }
3107  }
3108  else
3109  usec = atoi(argv[1]);
3110 
3111  if (argc > 2)
3112  {
3113  if (pg_strcasecmp(argv[2], "ms") == 0)
3114  usec *= 1000;
3115  else if (pg_strcasecmp(argv[2], "s") == 0)
3116  usec *= 1000000;
3117  }
3118  else
3119  usec *= 1000000;
3120 
3121  *usecs = usec;
3122  return true;
3123 }
#define pg_log_error(...)
Definition: logging.h:80
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1455
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3617 of file pgbench.c.

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

Referenced by advanceConnectionState().

3618 {
3619  Command *command = sql_script[st->use_file].commands[st->command];
3620  int argc;
3621  char **argv;
3622 
3623  Assert(command != NULL && command->type == META_COMMAND);
3624 
3625  argc = command->argc;
3626  argv = command->argv;
3627 
3629  {
3631 
3632  initPQExpBuffer(&buf);
3633 
3634  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
3635  for (int i = 1; i < argc; i++)
3636  appendPQExpBuffer(&buf, " %s", argv[i]);
3637 
3638  pg_log_debug("%s", buf.data);
3639 
3640  termPQExpBuffer(&buf);
3641  }
3642 
3643  if (command->meta == META_SLEEP)
3644  {
3645  int usec;
3646 
3647  /*
3648  * A \sleep doesn't execute anything, we just get the delay from the
3649  * argument, and enter the CSTATE_SLEEP state. (The per-command
3650  * latency will be recorded in CSTATE_SLEEP state, not here, after the
3651  * delay has elapsed.)
3652  */
3653  if (!evaluateSleep(st, argc, argv, &usec))
3654  {
3655  commandFailed(st, "sleep", "execution of meta-command failed");
3656  return CSTATE_ABORTED;
3657  }
3658 
3660  st->sleep_until = (*now) + usec;
3661  return CSTATE_SLEEP;
3662  }
3663  else if (command->meta == META_SET)
3664  {
3665  PgBenchExpr *expr = command->expr;
3666  PgBenchValue result;
3667 
3668  if (!evaluateExpr(st, expr, &result))
3669  {
3670  commandFailed(st, argv[0], "evaluation of meta-command failed");
3671  return CSTATE_ABORTED;
3672  }
3673 
3674  if (!putVariableValue(st, argv[0], argv[1], &result))
3675  {
3676  commandFailed(st, "set", "assignment of meta-command failed");
3677  return CSTATE_ABORTED;
3678  }
3679  }
3680  else if (command->meta == META_IF)
3681  {
3682  /* backslash commands with an expression to evaluate */
3683  PgBenchExpr *expr = command->expr;
3684  PgBenchValue result;
3685  bool cond;
3686 
3687  if (!evaluateExpr(st, expr, &result))
3688  {
3689  commandFailed(st, argv[0], "evaluation of meta-command failed");
3690  return CSTATE_ABORTED;
3691  }
3692 
3693  cond = valueTruth(&result);
3695  }
3696  else if (command->meta == META_ELIF)
3697  {
3698  /* backslash commands with an expression to evaluate */
3699  PgBenchExpr *expr = command->expr;
3700  PgBenchValue result;
3701  bool cond;
3702 
3704  {
3705  /* elif after executed block, skip eval and wait for endif. */
3707  return CSTATE_END_COMMAND;
3708  }
3709 
3710  if (!evaluateExpr(st, expr, &result))
3711  {
3712  commandFailed(st, argv[0], "evaluation of meta-command failed");
3713  return CSTATE_ABORTED;
3714  }
3715 
3716  cond = valueTruth(&result);
3719  }
3720  else if (command->meta == META_ELSE)
3721  {
3722  switch (conditional_stack_peek(st->cstack))
3723  {
3724  case IFSTATE_TRUE:
3726  break;
3727  case IFSTATE_FALSE: /* inconsistent if active */
3728  case IFSTATE_IGNORED: /* inconsistent if active */
3729  case IFSTATE_NONE: /* else without if */
3730  case IFSTATE_ELSE_TRUE: /* else after else */
3731  case IFSTATE_ELSE_FALSE: /* else after else */
3732  default:
3733  /* dead code if conditional check is ok */
3734  Assert(false);
3735  }
3736  }
3737  else if (command->meta == META_ENDIF)
3738  {
3741  }
3742  else if (command->meta == META_SETSHELL)
3743  {
3744  if (!runShellCommand(st, argv[1], argv + 2, argc - 2))
3745  {
3746  commandFailed(st, "setshell", "execution of meta-command failed");
3747  return CSTATE_ABORTED;
3748  }
3749  }
3750  else if (command->meta == META_SHELL)
3751  {
3752  if (!runShellCommand(st, NULL, argv + 1, argc - 1))
3753  {
3754  commandFailed(st, "shell", "execution of meta-command failed");
3755  return CSTATE_ABORTED;
3756  }
3757  }
3758  else if (command->meta == META_STARTPIPELINE)
3759  {
3760  /*
3761  * In pipeline mode, we use a workflow based on libpq pipeline
3762  * functions.
3763  */
3764  if (querymode == QUERY_SIMPLE)
3765  {
3766  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
3767  return CSTATE_ABORTED;
3768  }
3769 
3770  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3771  {
3772  commandFailed(st, "startpipeline", "already in pipeline mode");
3773  return CSTATE_ABORTED;
3774  }
3775  if (PQenterPipelineMode(st->con) == 0)
3776  {
3777  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
3778  return CSTATE_ABORTED;
3779  }
3780  }
3781  else if (command->meta == META_ENDPIPELINE)
3782  {
3783  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3784  {
3785  commandFailed(st, "endpipeline", "not in pipeline mode");
3786  return CSTATE_ABORTED;
3787  }
3788  if (!PQpipelineSync(st->con))
3789  {
3790  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
3791  return CSTATE_ABORTED;
3792  }
3793  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
3794  /* collect pending results before getting out of pipeline mode */
3795  return CSTATE_WAIT_RESULT;
3796  }
3797 
3798  /*
3799  * executing the expression or shell command might have taken a
3800  * non-negligible amount of time, so reset 'now'
3801  */
3802  *now = 0;
3803 
3804  return CSTATE_END_COMMAND;
3805 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
int type
Definition: pgbench.c:583
int id
Definition: pgbench.c:456
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:2894
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:2837
PgBenchExpr * expr
Definition: pgbench.c:588
char * argv[MAX_ARGS]
Definition: pgbench.c:586
ConditionalStack cstack
Definition: pgbench.c:458
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2645
#define META_COMMAND
Definition: pgbench.c:523
#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:584
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:600
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3077
enum pg_log_level __pg_log_level
Definition: logging.c:21
int argc
Definition: pgbench.c:585
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:691
int command
Definition: pgbench.c:467
static bool runShellCommand(CState *st, char *variable, char **argv, int argc)
Definition: pgbench.c:2729
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:94
static bool evaluateSleep(CState *st, int argc, char **argv, int *usecs)
Definition: pgbench.c:3085
PGconn * con
Definition: pgbench.c:455
#define Assert(condition)
Definition: c.h:804
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:6786
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:1837
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:106
Command ** commands
Definition: pgbench.c:596
static QueryMode querymode
Definition: pgbench.c:556
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:1666
#define unlikely(x)
Definition: c.h:273
pg_time_usec_t sleep_until
Definition: pgbench.c:476
int use_file
Definition: pgbench.c:466
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1544
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ executeStatement()

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

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

1325 {
1326  PGresult *res;
1327 
1328  res = PQexec(con, sql);
1329  if (PQresultStatus(res) != PGRES_COMMAND_OK)
1330  {
1331  pg_log_fatal("query failed: %s", PQerrorMessage(con));
1332  pg_log_info("query was: %s", sql);
1333  exit(1);
1334  }
1335  PQclear(res);
1336 }
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6744
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3178
void PQclear(PGresult *res)
Definition: fe-exec.c:694
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2193
#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 5351 of file pgbench.c.

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

Referenced by main().

5352 {
5353  int i,
5354  found = 0,
5355  len = strlen(name);
5356  const BuiltinScript *result = NULL;
5357 
5358  for (i = 0; i < lengthof(builtin_script); i++)
5359  {
5360  if (strncmp(builtin_script[i].name, name, len) == 0)
5361  {
5362  result = &builtin_script[i];
5363  found++;
5364  }
5365  }
5366 
5367  /* ok, unambiguous result */
5368  if (found == 1)
5369  return result;
5370 
5371  /* error cases */
5372  if (found == 0)
5373  pg_log_fatal("no builtin script found for name \"%s\"", name);
5374  else /* found > 1 */
5375  pg_log_fatal("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
5376 
5378  exit(1);
5379 }
static void listAvailableScripts(void)
Definition: pgbench.c:5339
#define lengthof(array)
Definition: c.h:734
static const BuiltinScript builtin_script[]
Definition: pgbench.c:612
const char * name
Definition: encode.c:561
int i
#define pg_log_fatal(...)
Definition: logging.h:76

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 6882 of file pgbench.c.

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

6883 {
6884  if (st->con != NULL)
6885  {
6886  PQfinish(st->con);
6887  st->con = NULL;
6888  }
6889 }
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4231
PGconn * con
Definition: pgbench.c:455

◆ free_command()

static void free_command ( Command command)
static

Definition at line 4804 of file pgbench.c.

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

Referenced by ParseScript().

4805 {
4806  termPQExpBuffer(&command->lines);
4807  if (command->first_line)
4808  pg_free(command->first_line);
4809  for (int i = 0; i < command->argc; i++)
4810  pg_free(command->argv[i]);
4811  if (command->varprefix)
4812  pg_free(command->varprefix);
4813 
4814  /*
4815  * It should also free expr recursively, but this is currently not needed
4816  * as only gset commands (which do not have an expression) are freed.
4817  */
4818  pg_free(command);
4819 }
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
char * argv[MAX_ARGS]
Definition: pgbench.c:586
PQExpBufferData lines
Definition: pgbench.c:581
int argc
Definition: pgbench.c:585
char * varprefix
Definition: pgbench.c:587
void pg_free(void *ptr)
Definition: fe_memutils.c:105
int i
char * first_line
Definition: pgbench.c:582

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 7056 of file pgbench.c.

References pg_free().

Referenced by setalarm(), and threadRun().

7057 {
7058  pg_free(sa);
7059 }
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 945 of file pgbench.c.

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

Referenced by evalStandardFunc().

947 {
948  double cut,
949  uniform,
950  rand;
951 
952  /* abort if wrong parameter, but must really be checked beforehand */
953  Assert(parameter > 0.0);
954  cut = exp(-parameter);
955  /* erand in [0, 1), uniform in (0, 1] */
956  uniform = 1.0 - pg_erand48(random_state->xseed);
957 
958  /*
959  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
960  */
961  Assert((1.0 - cut) != 0.0);
962  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
963  /* return int64 random number within between min and max */
964  return min + (int64) ((max - min + 1) * rand);
965 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:804
unsigned short xseed[3]
Definition: pgbench.c:358

◆ getGaussianRand()

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

Definition at line 969 of file pgbench.c.

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

Referenced by evalStandardFunc().

971 {
972  double stdev;
973  double rand;
974 
975  /* abort if parameter is too low, but must really be checked beforehand */
976  Assert(parameter >= MIN_GAUSSIAN_PARAM);
977 
978  /*
979  * Get user specified random number from this loop, with -parameter <
980  * stdev <= parameter
981  *
982  * This loop is executed until the number is in the expected range.
983  *
984  * As the minimum parameter is 2.0, the probability of looping is low:
985  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
986  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
987  * the worst case. For a parameter value of 5.0, the looping probability
988  * is about e^{-5} * 2 / pi ~ 0.43%.
989  */
990  do
991  {
992  /*
993  * pg_erand48 generates [0,1), but for the basic version of the
994  * Box-Muller transform the two uniformly distributed random numbers
995  * are expected in (0, 1] (see
996  * https://en.wikipedia.org/wiki/Box-Muller_transform)
997  */
998  double rand1 = 1.0 - pg_erand48(random_state->xseed);
999  double rand2 = 1.0 - pg_erand48(random_state->xseed);
1000 
1001  /* Box-Muller basic form transform */
1002  double var_sqrt = sqrt(-2.0 * log(rand1));
1003 
1004  stdev = var_sqrt * sin(2.0 * M_PI * rand2);
1005 
1006  /*
1007  * we may try with cos, but there may be a bias induced if the
1008  * previous value fails the test. To be on the safe side, let us try
1009  * over.
1010  */
1011  }
1012  while (stdev < -parameter || stdev >= parameter);
1013 
1014  /* stdev is in [-parameter, parameter), normalization to [0,1) */
1015  rand = (stdev + parameter) / (parameter * 2.0);
1016 
1017  /* return int64 random number within between min and max */
1018  return min + (int64) ((max - min + 1) * rand);
1019 }
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:178
#define M_PI
Definition: pgbench.c:75
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
#define Assert(condition)
Definition: c.h:804
unsigned short xseed[3]
Definition: pgbench.c:358

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1095 of file pgbench.c.

References FNV_OFFSET_BASIS, FNV_PRIME, and i.

Referenced by evalStandardFunc().

1096 {
1097  int64 result;
1098  int i;
1099 
1100  result = FNV_OFFSET_BASIS ^ seed;
1101  for (i = 0; i < 8; ++i)
1102  {
1103  int32 octet = val & 0xff;
1104 
1105  val = val >> 8;
1106  result = result ^ octet;
1107  result = result * FNV_PRIME;
1108  }
1109 
1110  return result;
1111 }
#define FNV_PRIME
Definition: pgbench.c:83
#define FNV_OFFSET_BASIS
Definition: pgbench.c:84
signed int int32
Definition: c.h:429
int i
long val
Definition: informix.c:664

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1120 of file pgbench.c.

References MM2_MUL, MM2_MUL_TIMES_8, and MM2_ROT.

Referenced by evalStandardFunc().

1121 {
1122  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1123  uint64 k = (uint64) val;
1124 
1125  k *= MM2_MUL;
1126  k ^= k >> MM2_ROT;
1127  k *= MM2_MUL;
1128 
1129  result ^= k;
1130  result *= MM2_MUL;
1131 
1132  result ^= result >> MM2_ROT;
1133  result *= MM2_MUL;
1134  result ^= result >> MM2_ROT;
1135 
1136  return (int64) result;
1137 }
#define MM2_MUL_TIMES_8
Definition: pgbench.c:86
#define MM2_ROT
Definition: pgbench.c:87
long val
Definition: informix.c:664
#define MM2_MUL
Definition: pgbench.c:85

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2689 of file pgbench.c.

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

Referenced by process_backslash_command().

2690 {
2691  MetaCommand mc;
2692 
2693  if (cmd == NULL)
2694  mc = META_NONE;
2695  else if (pg_strcasecmp(cmd, "set") == 0)
2696  mc = META_SET;
2697  else if (pg_strcasecmp(cmd, "setshell") == 0)
2698  mc = META_SETSHELL;
2699  else if (pg_strcasecmp(cmd, "shell") == 0)
2700  mc = META_SHELL;
2701  else if (pg_strcasecmp(cmd, "sleep") == 0)
2702  mc = META_SLEEP;
2703  else if (pg_strcasecmp(cmd, "if") == 0)
2704  mc = META_IF;
2705  else if (pg_strcasecmp(cmd, "elif") == 0)
2706  mc = META_ELIF;
2707  else if (pg_strcasecmp(cmd, "else") == 0)
2708  mc = META_ELSE;
2709  else if (pg_strcasecmp(cmd, "endif") == 0)
2710  mc = META_ENDIF;
2711  else if (pg_strcasecmp(cmd, "gset") == 0)
2712  mc = META_GSET;
2713  else if (pg_strcasecmp(cmd, "aset") == 0)
2714  mc = META_ASET;
2715  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2716  mc = META_STARTPIPELINE;
2717  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2718  mc = META_ENDPIPELINE;
2719  else
2720  mc = META_NONE;
2721  return mc;
2722 }
MetaCommand
Definition: pgbench.c:531
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 1029 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by advanceConnectionState().

1030 {
1031  /*
1032  * Use inverse transform sampling to generate a value > 0, such that the
1033  * expected (i.e. average) value is the given argument.
1034  */
1035  double uniform;
1036 
1037  /* erand in [0, 1), uniform in (0, 1] */
1038  uniform = 1.0 - pg_erand48(random_state->xseed);
1039 
1040  return (int64) (-log(uniform) * center + 0.5);
1041 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:358

◆ getQueryParams()

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

Definition at line 1786 of file pgbench.c.

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

Referenced by sendCommand().

1787 {
1788  int i;
1789 
1790  for (i = 0; i < command->argc - 1; i++)
1791  params[i] = getVariable(st, command->argv[i + 1]);
1792 }
static char * getVariable(CState *st, char *name)
Definition: pgbench.c:1455
char * argv[MAX_ARGS]
Definition: pgbench.c:586
int argc
Definition: pgbench.c:585
int i

◆ getrand()

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

Definition at line 925 of file pgbench.c.

References pg_erand48(), and RandomState::xseed.

Referenced by chooseScript(), evalStandardFunc(), and permute().

926 {
927  /*
928  * Odd coding is so that min and max have approximately the same chance of
929  * being selected as do numbers between them.
930  *
931  * pg_erand48() is thread-safe and concurrent, which is why we use it
932  * rather than random(), which in glibc is non-reentrant, and therefore
933  * protected by a mutex, and therefore a bottleneck on machines with many
934  * CPUs.
935  */
936  return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
937 }
double pg_erand48(unsigned short xseed[3])
Definition: erand48.c:88
unsigned short xseed[3]
Definition: pgbench.c:358

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 4533 of file pgbench.c.

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

Referenced by main().

4534 {
4535  PGresult *res;
4536 
4537  /*
4538  * get the scaling factor that should be same as count(*) from
4539  * pgbench_branches if this is not a custom query
4540  */
4541  res = PQexec(con, "select count(*) from pgbench_branches");
4542  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4543  {
4544  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
4545 
4546  pg_log_fatal("could not count number of branches: %s", PQerrorMessage(con));
4547 
4548  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
4549  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\"",
4550  PQdb(con));
4551 
4552  exit(1);
4553  }
4554  scale = atoi(PQgetvalue(res, 0, 0));
4555  if (scale < 0)
4556  {
4557  pg_log_fatal("invalid count(*) from pgbench_branches: \"%s\"",
4558  PQgetvalue(res, 0, 0));
4559  exit(1);
4560  }
4561  PQclear(res);
4562 
4563  /* warn if we override user-given -s switch */
4564  if (scale_given)
4565  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
4566  scale);
4567 
4568  /*
4569  * Get the partition information for the first "pgbench_accounts" table
4570  * found in search_path.
4571  *
4572  * The result is empty if no "pgbench_accounts" is found.
4573  *
4574  * Otherwise, it always returns one row even if the table is not
4575  * partitioned (in which case the partition strategy is NULL).
4576  *
4577  * The number of partitions can be 0 even for partitioned tables, if no
4578  * partition is attached.
4579  *
4580  * We assume no partitioning on any failure, so as to avoid failing on an
4581  * old version without "pg_partitioned_table".
4582  */
4583  res = PQexec(con,
4584  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
4585  "from pg_catalog.pg_class as c "
4586  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
4587  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
4588  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
4589  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
4590  "where c.relname = 'pgbench_accounts' and o.n is not null "
4591  "group by 1, 2 "
4592  "order by 1 asc "
4593  "limit 1");
4594 
4595  if (PQresultStatus(res) != PGRES_TUPLES_OK)
4596  {
4597  /* probably an older version, coldly assume no partitioning */
4599  partitions = 0;
4600  }
4601  else if (PQntuples(res) == 0)
4602  {
4603  /*
4604  * This case is unlikely as pgbench already found "pgbench_branches"
4605  * above to compute the scale.
4606  */
4607  pg_log_fatal("no pgbench_accounts table found in search_path");
4608  pg_log_info("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
4609  exit(1);
4610  }
4611  else /* PQntupes(res) == 1 */
4612  {
4613  /* normal case, extract partition information */
4614  if (PQgetisnull(res, 0, 1))
4616  else
4617  {
4618  char *ps = PQgetvalue(res, 0, 1);
4619 
4620  /* column must be there */
4621  Assert(ps != NULL);
4622 
4623  if (strcmp(ps, "r") == 0)
4625  else if (strcmp(ps, "h") == 0)
4627  else
4628  {
4629  /* possibly a newer version with new partition method */
4630  pg_log_fatal("unexpected partition method: \"%s\"", ps);
4631  exit(1);
4632  }
4633  }
4634 
4635  partitions = atoi(PQgetvalue(res, 0, 2));
4636  }
4637 
4638  PQclear(res);
4639 }
static int partitions
Definition: pgbench.c:233
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6744
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3642
static partition_method_t partition_method
Definition: pgbench.c:243
int scale
Definition: pgbench.c:191
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3248
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3178
void PQclear(PGresult *res)
Definition: fe-exec.c:694
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6590
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3233
#define Assert(condition)
Definition: c.h:804
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2193
#define pg_log_warning(...)
Definition: pgfnames.c:24
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3667
#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 1455 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().

1456 {
1457  Variable *var;
1458  char stringform[64];
1459 
1460  var = lookupVariable(st, name);
1461  if (var == NULL)
1462  return NULL; /* not found */
1463 
1464  if (var->svalue)
1465  return var->svalue; /* we have it in string form */
1466 
1467  /* We need to produce a string equivalent of the value */
1468  Assert(var->value.type != PGBT_NO_VALUE);
1469  if (var->value.type == PGBT_NULL)
1470  snprintf(stringform, sizeof(stringform), "NULL");
1471  else if (var->value.type == PGBT_BOOLEAN)
1472  snprintf(stringform, sizeof(stringform),
1473  "%s", var->value.u.bval ? "true" : "false");
1474  else if (var->value.type == PGBT_INT)
1475  snprintf(stringform, sizeof(stringform),
1476  INT64_FORMAT, var->value.u.ival);
1477  else if (var->value.type == PGBT_DOUBLE)
1478  snprintf(stringform, sizeof(stringform),
1479  "%.*g", DBL_DIG, var->value.u.dval);
1480  else /* internal error, unexpected type */
1481  Assert(0);
1482  var->svalue = pg_strdup(stringform);
1483  return var->svalue;
1484 }
static Variable * lookupVariable(CState *st, char *name)
Definition: pgbench.c:1428
union PgBenchValue::@31 u
char * svalue
Definition: pgbench.c:304
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
PgBenchValue value
Definition: pgbench.c:305
double dval
Definition: pgbench.h:50
#define Assert(condition)
Definition: c.h:804
#define INT64_FORMAT
Definition: c.h:483
const char * name
Definition: encode.c:561
bool bval
Definition: pgbench.h:51
PgBenchValueType type
Definition: pgbench.h:46
int64 ival
Definition: pgbench.h:49
#define snprintf
Definition: port.h:216

◆ getZipfianRand()

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

Definition at line 1081 of file pgbench.c.

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

Referenced by evalStandardFunc().

1082 {
1083  int64 n = max - min + 1;
1084 
1085  /* abort if parameter is invalid */
1087 
1088  return min - 1 + computeIterativeZipfian(random_state, n, s);
1089 }
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:181
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:180
#define Assert(condition)
Definition: c.h:804
static int64 computeIterativeZipfian(RandomState *random_state, int64 n, double s)
Definition: pgbench.c:1051

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 6898 of file pgbench.c.

References timer_exceeded.

Referenced by setalarm().

6899 {
6900  timer_exceeded = true;
6901 }
volatile bool timer_exceeded
Definition: pgbench.c:289

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 4399 of file pgbench.c.

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

Referenced by runInitSteps().

4400 {
4401  static const char *const DDLKEYs[] = {
4402  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
4403  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
4404  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
4405  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
4406  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
4407  };
4408  int i;
4409 
4410  fprintf(stderr, "creating foreign keys...\n");
4411  for (i = 0; i < lengthof(DDLKEYs); i++)
4412  {
4413  executeStatement(con, DDLKEYs[i]);
4414  }
4415 }
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
int i

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 4361 of file pgbench.c.

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

Referenced by runInitSteps().

4362 {
4363  static const char *const DDLINDEXes[] = {
4364  "alter table pgbench_branches add primary key (bid)",
4365  "alter table pgbench_tellers add primary key (tid)",
4366  "alter table pgbench_accounts add primary key (aid)"
4367  };
4368  int i;
4369  PQExpBufferData query;
4370 
4371  fprintf(stderr, "creating primary keys...\n");
4372  initPQExpBuffer(&query);
4373 
4374  for (i = 0; i < lengthof(DDLINDEXes); i++)
4375  {
4376  resetPQExpBuffer(&query);
4377  appendPQExpBufferStr(&query, DDLINDEXes[i]);
4378 
4379  if (index_tablespace != NULL)
4380  {
4381  char *escape_tablespace;
4382 
4383  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
4384  strlen(index_tablespace));
4385  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
4386  PQfreemem(escape_tablespace);
4387  }
4388 
4389  executeStatement(con, query.data);
4390  }
4391 
4392  termPQExpBuffer(&query);
4393 }
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:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4075
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * index_tablespace
Definition: pgbench.c:227
int i
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:148
void PQfreemem(void *ptr)
Definition: fe-exec.c:3796
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4047 of file pgbench.c.

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

Referenced by runInitSteps().

4048 {
4049  /*
4050  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4051  * fields in these table declarations were intended to comply with that.
4052  * The pgbench_accounts table complies with that because the "filler"
4053  * column is set to blank-padded empty string. But for all other tables
4054  * the columns default to NULL and so don't actually take any space. We
4055  * could fix that by giving them non-null default values. However, that
4056  * would completely break comparability of pgbench results with prior
4057  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4058  * anyway, we stick with the historical behavior.
4059  */
4060  struct ddlinfo
4061  {
4062  const char *table; /* table name */
4063  const char *smcols; /* column decls if accountIDs are 32 bits */
4064  const char *bigcols; /* column decls if accountIDs are 64 bits */
4065  int declare_fillfactor;
4066  };
4067  static const struct ddlinfo DDLs[] = {
4068  {
4069  "pgbench_history",
4070  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4071  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4072  0
4073  },
4074  {
4075  "pgbench_tellers",
4076  "tid int not null,bid int,tbalance int,filler char(84)",
4077  "tid int not null,bid int,tbalance int,filler char(84)",
4078  1
4079  },
4080  {
4081  "pgbench_accounts",
4082  "aid int not null,bid int,abalance int,filler char(84)",
4083  "aid bigint not null,bid int,abalance int,filler char(84)",
4084  1
4085  },
4086  {
4087  "pgbench_branches",
4088  "bid int not null,bbalance int,filler char(88)",
4089  "bid int not null,bbalance int,filler char(88)",
4090  1
4091  }
4092  };
4093  int i;
4094  PQExpBufferData query;
4095 
4096  fprintf(stderr, "creating tables...\n");
4097 
4098  initPQExpBuffer(&query);
4099 
4100  for (i = 0; i < lengthof(DDLs); i++)
4101  {
4102  const struct ddlinfo *ddl = &DDLs[i];
4103 
4104  /* Construct new create table statement. */
4105  printfPQExpBuffer(&query, "create%s table %s(%s)",
4106  unlogged_tables ? " unlogged" : "",
4107  ddl->table,
4108  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4109 
4110  /* Partition pgbench_accounts table */
4111  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4112  appendPQExpBuffer(&query,
4113  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4114  else if (ddl->declare_fillfactor)
4115  {
4116  /* fillfactor is only expected on actual tables */
4117  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4118  }
4119 
4120  if (tablespace != NULL)
4121  {
4122  char *escape_tablespace;
4123 
4124  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4125  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4126  PQfreemem(escape_tablespace);
4127  }
4128 
4129  executeStatement(con, query.data);
4130  }
4131 
4132  termPQExpBuffer(&query);
4133 
4134  if (partition_method != PART_NONE)
4135  createPartitions(con);
4136 }
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:243
int scale
Definition: pgbench.c:191
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:265
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4075
int fillfactor
Definition: pgbench.c:197
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:267
char * tablespace
Definition: pgbench.c:226
static const char * PARTITION_METHOD[]
Definition: pgbench.c:244
bool unlogged_tables
Definition: pgbench.c:202
int i
static void createPartitions(PGconn *con)
Definition: pgbench.c:3978
void PQfreemem(void *ptr)
Definition: fe-exec.c:3796
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 3956 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

3957 {
3958  fprintf(stderr, "dropping old tables...\n");
3959 
3960  /*
3961  * We drop all the tables in one command, so that whether there are
3962  * foreign key dependencies or not doesn't matter.
3963  */
3964  executeStatement(con, "drop table if exists "
3965  "pgbench_accounts, "
3966  "pgbench_branches, "
3967  "pgbench_history, "
3968  "pgbench_tellers");
3969 }
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 4155 of file pgbench.c.

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

Referenced by runInitSteps().

4156 {
4157  PQExpBufferData sql;
4158  PGresult *res;
4159  int i;
4160  int64 k;
4161  char *copy_statement;
4162 
4163  /* used to track elapsed time and estimate of the remaining time */
4164  pg_time_usec_t start;
4165  int log_interval = 1;
4166 
4167  /* Stay on the same line if reporting to a terminal */
4168  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4169 
4170  fprintf(stderr, "generating data (client-side)...\n");
4171 
4172  /*
4173  * we do all of this in one transaction to enable the backend's
4174  * data-loading optimizations
4175  */
4176  executeStatement(con, "begin");
4177 
4178  /* truncate away any old data */
4179  initTruncateTables(con);
4180 
4181  initPQExpBuffer(&sql);
4182 
4183  /*
4184  * fill branches, tellers, accounts in that order in case foreign keys
4185  * already exist
4186  */
4187  for (i = 0; i < nbranches * scale; i++)
4188  {
4189  /* "filler" column defaults to NULL */
4190  printfPQExpBuffer(&sql,
4191  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4192  i + 1);
4193  executeStatement(con, sql.data);
4194  }
4195 
4196  for (i = 0; i < ntellers * scale; i++)
4197  {
4198  /* "filler" column defaults to NULL */
4199  printfPQExpBuffer(&sql,
4200  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4201  i + 1, i / ntellers + 1);
4202  executeStatement(con, sql.data);
4203  }
4204 
4205  /*
4206  * accounts is big enough to be worth using COPY and tracking runtime
4207  */
4208 
4209  /* use COPY with FREEZE on v14 and later without partioning */
4210  if (partitions == 0 && PQserverVersion(con) >= 140000)
4211  copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4212  else
4213  copy_statement = "copy pgbench_accounts from stdin";
4214 
4215  res = PQexec(con, copy_statement);
4216 
4217  if (PQresultStatus(res) != PGRES_COPY_IN)
4218  {
4219  pg_log_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4220  exit(1);
4221  }
4222  PQclear(res);
4223 
4224  start = pg_time_now();
4225 
4226  for (k = 0; k < (int64) naccounts * scale; k++)
4227  {
4228  int64 j = k + 1;
4229 
4230  /* "filler" column defaults to blank padded empty string */
4231  printfPQExpBuffer(&sql,
4232  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4233  j, k / naccounts + 1, 0);
4234  if (PQputline(con, sql.data))
4235  {
4236  pg_log_fatal("PQputline failed");
4237  exit(1);
4238  }
4239 
4240  if (CancelRequested)
4241  break;
4242 
4243  /*
4244  * If we want to stick with the original logging, print a message each
4245  * 100k inserted rows.
4246  */
4247  if ((!use_quiet) && (j % 100000 == 0))
4248  {
4249  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4250  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4251 
4252  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4253  j, (int64) naccounts * scale,
4254  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4255  elapsed_sec, remaining_sec, eol);
4256  }
4257  /* let's not call the timing for each row, but only each 100 rows */
4258  else if (use_quiet && (j % 100 == 0))
4259  {
4260  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4261  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4262 
4263  /* have we reached the next interval (or end)? */
4264  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4265  {
4266  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4267  j, (int64) naccounts * scale,
4268  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4269 
4270  /* skip to the next interval */
4271  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4272  }
4273  }
4274  }
4275 
4276  if (eol != '\n')
4277  fputc('\n', stderr); /* Need to move to next line */
4278 
4279  if (PQputline(con, "\\.\n"))
4280  {
4281  pg_log_fatal("very last PQputline failed");
4282  exit(1);
4283  }
4284  if (PQendcopy(con))
4285  {
4286  pg_log_fatal("PQendcopy failed");
4287  exit(1);
4288  }
4289 
4290  termPQExpBuffer(&sql);
4291 
4292  executeStatement(con, "commit");
4293 }
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:697
static int partitions
Definition: pgbench.c:233
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:6744
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:681
int64 pg_time_usec_t
Definition: pgbench.c:331
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:191
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6734
#define LOG_STEP_SECONDS
Definition: pgbench.c:175
#define fprintf
Definition: port.h:220
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3178
bool use_quiet
Definition: pgbench.c:268
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
int PQputline(PGconn *conn, const char *s)
Definition: fe-exec.c:2771
#define nbranches
Definition: pgbench.c:253
#define ntellers
Definition: pgbench.c:255
#define naccounts
Definition: pgbench.c:256
void PQclear(PGresult *res)
Definition: fe-exec.c:694
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2802
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4142
#define INT64_FORMAT
Definition: c.h:483
volatile sig_atomic_t CancelRequested
Definition: cancel.c:52
int i
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2193
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 4303 of file pgbench.c.

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

Referenced by runInitSteps().

4304 {
4305  PQExpBufferData sql;
4306 
4307  fprintf(stderr, "generating data (server-side)...\n");
4308 
4309  /*
4310  * we do all of this in one transaction to enable the backend's
4311  * data-loading optimizations
4312  */
4313  executeStatement(con, "begin");
4314 
4315  /* truncate away any old data */
4316  initTruncateTables(con);
4317 
4318  initPQExpBuffer(&sql);
4319 
4320  printfPQExpBuffer(&sql,
4321  "insert into pgbench_branches(bid,bbalance) "
4322  "select bid, 0 "
4323  "from generate_series(1, %d) as bid", nbranches * scale);
4324  executeStatement(con, sql.data);
4325 
4326  printfPQExpBuffer(&sql,
4327  "insert into pgbench_tellers(tid,bid,tbalance) "
4328  "select tid, (tid - 1) / %d + 1, 0 "
4329  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
4330  executeStatement(con, sql.data);
4331 
4332  printfPQExpBuffer(&sql,
4333  "insert into pgbench_accounts(aid,bid,abalance,filler) "
4334  "select aid, (aid - 1) / %d + 1, 0, '' "
4335  "from generate_series(1, " INT64_FORMAT ") as aid",
4336  naccounts, (int64) naccounts * scale);
4337  executeStatement(con, sql.data);
4338 
4339  termPQExpBuffer(&sql);
4340 
4341  executeStatement(con, "commit");
4342 }
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:237
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:131
int scale
Definition: pgbench.c:191
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324
#define nbranches
Definition: pgbench.c:253
#define ntellers
Definition: pgbench.c:255
#define naccounts
Definition: pgbench.c:256
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4142
#define INT64_FORMAT
Definition: c.h:483
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:92

◆ initRandomState()

static void initRandomState ( RandomState random_state)
static

Definition at line 906 of file pgbench.c.

References pg_jrand48(), and RandomState::xseed.

Referenced by main().

907 {
908  random_state->xseed[0] = (unsigned short)
910  random_state->xseed[1] = (unsigned short)
912  random_state->xseed[2] = (unsigned short)
914 }
static RandomState base_random_sequence
Definition: pgbench.c:362
unsigned short xseed[3]
Definition: pgbench.c:358
long pg_jrand48(unsigned short xseed[3])
Definition: erand48.c:112

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1250 of file pgbench.c.

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

1251 {
1252  memset(ss, 0, sizeof(SimpleStats));
1253 }

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

Definition at line 1290 of file pgbench.c.

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

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

1291 {
1292  sd->start_time = start;
1293  sd->cnt = 0;
1294  sd->skipped = 0;
1295  initSimpleStats(&sd->latency);
1296  initSimpleStats(&sd->lag);
1297 }
pg_time_usec_t start_time
Definition: pgbench.c:339
SimpleStats lag
Definition: pgbench.c:344
SimpleStats latency
Definition: pgbench.c:343
int64 cnt
Definition: pgbench.c:340
int64 skipped
Definition: pgbench.c:341
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1250

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4142 of file pgbench.c.

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

4143 {
4144  executeStatement(con, "truncate table "
4145  "pgbench_accounts, "
4146  "pgbench_branches, "
4147  "pgbench_history, "
4148  "pgbench_tellers");
4149 }
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 4348 of file pgbench.c.

References executeStatement(), and fprintf.

Referenced by runInitSteps().

4349 {
4350  fprintf(stderr, "vacuuming...\n");
4351  executeStatement(con, "vacuum analyze pgbench_branches");
4352  executeStatement(con, "vacuum analyze pgbench_tellers");
4353  executeStatement(con, "vacuum analyze pgbench_accounts");
4354  executeStatement(con, "vacuum analyze pgbench_history");
4355 }
#define fprintf
Definition: port.h:220
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1324

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 769 of file pgbench.c.

References generate_unaccent_rules::str.

Referenced by makeVariableValue().

770 {
771  const char *ptr = str;
772 
773  /* skip leading spaces; cast is consistent with strtoint64 */
774  while (*ptr && isspace((unsigned char) *ptr))
775  ptr++;
776 
777  /* skip sign */
778  if (*ptr == '+' || *ptr == '-')
779  ptr++;
780 
781  /* at least one digit */
782  if (*ptr && !isdigit((unsigned char) *ptr))
783  return false;
784 
785  /* eat all digits */
786  while (*ptr && isdigit((unsigned char) *ptr))
787  ptr++;
788 
789  /* must have reached end of string */
790  return *ptr == '\0';
791 }

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 1938 of file pgbench.c.

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

1939 {
1940  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;
1941 }

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 5339 of file pgbench.c.

References fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

5340 {
5341  int i;
5342 
5343  fprintf(stderr, "Available builtin scripts:\n");
5344  for (i = 0; i < lengthof(builtin_script); i++)
5345  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
5346  fprintf(stderr, "\n");
5347 }
#define lengthof(array)
Definition: c.h:734
#define fprintf
Definition: port.h:220
static const BuiltinScript builtin_script[]
Definition: pgbench.c:612
const char * name
Definition: encode.c:561
int i

◆ lookupCreateVariable()

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

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

1599 {
1600  Variable *var;
1601 
1602  var = lookupVariable(st, name);
1603  if (var == NULL)
1604  {
1605  Variable *newvars;
1606 
1607  /*
1608  * Check for the name only when declaring a new variable to avoid
1609  * overhead.
1610  */
1611  if (!valid_variable_name(name))
1612  {
1613  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1614  return NULL;
1615  }
1616 
1617  /* Create variable at the end of the array */
1618  if (st->variables)
1619  newvars = (Variable *) pg_realloc(st->variables,
1620  (st->nvariables + 1) * sizeof(Variable));
1621  else
1622  newvars = (Variable *) pg_malloc(sizeof(Variable));
1623 
1624  st->variables = newvars;
1625 
1626  var = &newvars[st->nvariables];
1627 
1628  var->name = pg_strdup(name);
1629  var->svalue = NULL;
1630  /* caller is expected to initialize remaining fields */
1631 
1632  st->nvariables++;
1633  /* we don't re-sort the array till we have to */
1634  st->vars_sorted = false;
1635  }
<