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 <sys/resource.h>
#include <sys/select.h>
#include "common/int.h"
#include "common/logging.h"
#include "common/pg_prng.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 "port/pg_pthread.h"
Include dependency graph for pgbench.c:

Go to the source code of this file.

Data Structures

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

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"
 
#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"
 
#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   pthread_t
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_CREATE(handle, function, arg)    pthread_create((handle), NULL, (function), (arg))
 
#define THREAD_JOIN(handle)    pthread_join((handle), NULL)
 
#define THREAD_BARRIER_T   pthread_barrier_t
 
#define THREAD_BARRIER_INIT(barrier, n)    pthread_barrier_init((barrier), NULL, (n))
 
#define THREAD_BARRIER_WAIT(barrier)   pthread_barrier_wait((barrier))
 
#define THREAD_BARRIER_DESTROY(barrier)   pthread_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 VARIABLES_ALLOC_MARGIN   8
 
#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 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 enum EStatus EStatus
 
typedef enum TStatus TStatus
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 
typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  EStatus {
  ESTATUS_NO_ERROR = 0 , ESTATUS_META_COMMAND_ERROR , ESTATUS_SERIALIZATION_ERROR , ESTATUS_DEADLOCK_ERROR ,
  ESTATUS_OTHER_SQL_ERROR
}
 
enum  TStatus { TSTATUS_IDLE , TSTATUS_IN_BLOCK , TSTATUS_CONN_ERROR , TSTATUS_OTHER_ERROR }
 
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_ERROR , CSTATE_WAIT_ROLLBACK_RESULT , CSTATE_RETRY ,
  CSTATE_FAILURE , 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_SYNCPIPELINE , 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 (const 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 (pg_prng_state *state)
 
static int64 getrand (pg_prng_state *state, int64 min, int64 max)
 
static int64 getExponentialRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getGaussianRand (pg_prng_state *state, int64 min, int64 max, double parameter)
 
static int64 getPoissonRand (pg_prng_state *state, double center)
 
static int64 computeIterativeZipfian (pg_prng_state *state, int64 n, double s)
 
static int64 getZipfianRand (pg_prng_state *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, EStatus estatus, int64 tries)
 
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 (Variables *variables, char *name)
 
static char * getVariable (Variables *variables, char *name)
 
static bool makeVariableValue (Variable *var)
 
static bool valid_variable_name (const char *name)
 
static void enlargeVariables (Variables *variables, int needed)
 
static VariablelookupCreateVariable (Variables *variables, const char *context, char *name)
 
static bool putVariable (Variables *variables, const char *context, char *name, const char *value)
 
static bool putVariableValue (Variables *variables, const char *context, char *name, const PgBenchValue *value)
 
static bool putVariableInt (Variables *variables, 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 (Variables *variables, char *sql)
 
static void getQueryParams (Variables *variables, 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 (Variables *variables, char *variable, char **argv, int argc)
 
static void commandFailed (CState *st, const char *cmd, const char *message)
 
static void commandError (CState *st, const char *message)
 
static int chooseScript (TState *thread)
 
static void allocCStatePrepared (CState *st)
 
static void prepareCommand (CState *st, int command_num)
 
static void prepareCommandsInPipeline (CState *st)
 
static bool sendCommand (CState *st, Command *command)
 
static EStatus getSQLErrorStatus (const char *sqlState)
 
static bool canRetryError (EStatus estatus)
 
static bool readCommandResponse (CState *st, MetaCommand meta, char *varprefix)
 
static bool evaluateSleep (Variables *variables, int argc, char **argv, int *usecs)
 
static bool doRetry (CState *st, pg_time_usec_t *now)
 
static int discardUntilSync (CState *st)
 
static TStatus getTransactionStatus (PGconn *con)
 
static void printVerboseErrorMessages (CState *st, pg_time_usec_t *now, bool is_retry)
 
static void advanceConnectionState (TState *thread, CState *st, StatsData *agg)
 
static int64 getFailures (const StatsData *stats)
 
static const char * getResultString (bool skipped, EStatus estatus)
 
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 initBranch (PQExpBufferData *sql, int64 curr)
 
static void initTeller (PQExpBufferData *sql, int64 curr)
 
static void initAccount (PQExpBufferData *sql, int64 curr)
 
static void initPopulateTable (PGconn *con, const char *table, int64 base, initRowMethod init_row)
 
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 (const 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 *const 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 = false
 
int main_pid
 
uint32 max_tries = 1
 
bool failures_detailed = false
 
const char * pghost = NULL
 
const char * pgport = NULL
 
const char * username = NULL
 
const char * dbName = NULL
 
char * logfile_prefix = NULL
 
const char * progname
 
volatile sig_atomic_t timer_exceeded = false
 
pg_time_usec_t epoch_shift
 
static pg_prng_state base_random_sequence
 
static THREAD_BARRIER_T barrier
 
static QueryMode querymode = QUERY_SIMPLE
 
static const char *const QUERYMODE [] = {"simple", "extended", "prepared"}
 
static ParsedScript sql_script [MAX_SCRIPTS]
 
static int num_scripts
 
static int64 total_weight = 0
 
static bool verbose_errors = false
 
static bool exit_on_abort = false
 
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 163 of file pgbench.c.

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

◆ DEFAULT_INIT_STEPS

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

Definition at line 162 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 166 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 77 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 76 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 78 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 84 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 83 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 165 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 73 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 684 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2241 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 346 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 171 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 678 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 168 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 170 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 85 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 86 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 87 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 245 of file pgbench.c.

◆ nbranches

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

Definition at line 243 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 244 of file pgbench.c.

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

◆ PG_TIME_GET_DOUBLE

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

Definition at line 866 of file pgbench.c.

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 52 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 254 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

Definition at line 347 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 106 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 677 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)    pthread_barrier_destroy((barrier))

Definition at line 155 of file pgbench.c.

◆ THREAD_BARRIER_INIT

#define THREAD_BARRIER_INIT (   barrier,
 
)     pthread_barrier_init((barrier), NULL, (n))

Definition at line 152 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   pthread_barrier_t

Definition at line 151 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)    pthread_barrier_wait((barrier))

Definition at line 154 of file pgbench.c.

◆ THREAD_CREATE

#define THREAD_CREATE (   handle,
  function,
  arg 
)     pthread_create((handle), NULL, (function), (arg))

Definition at line 147 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 146 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 145 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 144 of file pgbench.c.

◆ THREAD_JOIN

#define THREAD_JOIN (   handle)     pthread_join((handle), NULL)

Definition at line 149 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   pthread_t

Definition at line 143 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 309 of file pgbench.c.

◆ WSEP

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

Definition at line 301 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ EStatus

typedef enum EStatus EStatus

◆ initRowMethod

typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)

Definition at line 842 of file pgbench.c.

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

Definition at line 369 of file pgbench.c.

◆ QueryMode

typedef enum QueryMode QueryMode

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

◆ TStatus

typedef enum TStatus TStatus

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_ERROR 
CSTATE_WAIT_ROLLBACK_RESULT 
CSTATE_RETRY 
CSTATE_FAILURE 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 484 of file pgbench.c.

486 {
487  /*
488  * The client must first choose a script to execute. Once chosen, it can
489  * either be throttled (state CSTATE_PREPARE_THROTTLE under --rate), start
490  * right away (state CSTATE_START_TX) or not start at all if the timer was
491  * exceeded (state CSTATE_FINISHED).
492  */
494 
495  /*
496  * CSTATE_START_TX performs start-of-transaction processing. Establishes
497  * a new connection for the transaction in --connect mode, records the
498  * transaction start time, and proceed to the first command.
499  *
500  * Note: once a script is started, it will either error or run till its
501  * end, where it may be interrupted. It is not interrupted while running,
502  * so pgbench --time is to be understood as tx are allowed to start in
503  * that time, and will finish when their work is completed.
504  */
506 
507  /*
508  * In CSTATE_PREPARE_THROTTLE state, we calculate when to begin the next
509  * transaction, and advance to CSTATE_THROTTLE. CSTATE_THROTTLE state
510  * sleeps until that moment, then advances to CSTATE_START_TX, or
511  * CSTATE_FINISHED if the next transaction would start beyond the end of
512  * the run.
513  */
516 
517  /*
518  * We loop through these states, to process each command in the script:
519  *
520  * CSTATE_START_COMMAND starts the execution of a command. On a SQL
521  * command, the command is sent to the server, and we move to
522  * CSTATE_WAIT_RESULT state unless in pipeline mode. On a \sleep
523  * meta-command, the timer is set, and we enter the CSTATE_SLEEP state to
524  * wait for it to expire. Other meta-commands are executed immediately. If
525  * the command about to start is actually beyond the end of the script,
526  * advance to CSTATE_END_TX.
527  *
528  * CSTATE_WAIT_RESULT waits until we get a result set back from the server
529  * for the current command.
530  *
531  * CSTATE_SLEEP waits until the end of \sleep.
532  *
533  * CSTATE_END_COMMAND records the end-of-command timestamp, increments the
534  * command counter, and loops back to CSTATE_START_COMMAND state.
535  *
536  * CSTATE_SKIP_COMMAND is used by conditional branches which are not
537  * executed. It quickly skip commands that do not need any evaluation.
538  * This state can move forward several commands, till there is something
539  * to do or the end of the script.
540  */
543  CSTATE_SLEEP,
546 
547  /*
548  * States for failed commands.
549  *
550  * If the SQL/meta command fails, in CSTATE_ERROR clean up after an error:
551  * (1) clear the conditional stack; (2) if we have an unterminated
552  * (possibly failed) transaction block, send the rollback command to the
553  * server and wait for the result in CSTATE_WAIT_ROLLBACK_RESULT. If
554  * something goes wrong with rolling back, go to CSTATE_ABORTED.
555  *
556  * But if everything is ok we are ready for future transactions: if this
557  * is a serialization or deadlock error and we can re-execute the
558  * transaction from the very beginning, go to CSTATE_RETRY; otherwise go
559  * to CSTATE_FAILURE.
560  *
561  * In CSTATE_RETRY report an error, set the same parameters for the
562  * transaction execution as in the previous tries and process the first
563  * transaction command in CSTATE_START_COMMAND.
564  *
565  * In CSTATE_FAILURE report a failure, set the parameters for the
566  * transaction execution as they were before the first run of this
567  * transaction (except for a random state) and go to CSTATE_END_TX to
568  * complete this transaction.
569  */
570  CSTATE_ERROR,
572  CSTATE_RETRY,
574 
575  /*
576  * CSTATE_END_TX performs end-of-transaction processing. It calculates
577  * latency, and logs the transaction. In --connect mode, it closes the
578  * current connection.
579  *
580  * Then either starts over in CSTATE_CHOOSE_SCRIPT, or enters
581  * CSTATE_FINISHED if we have no more work to do.
582  */
584 
585  /*
586  * Final states. CSTATE_ABORTED means that the script execution was
587  * aborted because a command failed, CSTATE_FINISHED means success.
588  */
@ CSTATE_START_TX
Definition: pgbench.c:504
@ CSTATE_END_TX
Definition: pgbench.c:582
@ CSTATE_RETRY
Definition: pgbench.c:571
@ CSTATE_FINISHED
Definition: pgbench.c:589
@ CSTATE_SKIP_COMMAND
Definition: pgbench.c:544
@ CSTATE_THROTTLE
Definition: pgbench.c:514
@ CSTATE_FAILURE
Definition: pgbench.c:572
@ CSTATE_START_COMMAND
Definition: pgbench.c:540
@ CSTATE_END_COMMAND
Definition: pgbench.c:543
@ CSTATE_WAIT_RESULT
Definition: pgbench.c:541
@ CSTATE_CHOOSE_SCRIPT
Definition: pgbench.c:492
@ CSTATE_WAIT_ROLLBACK_RESULT
Definition: pgbench.c:570
@ CSTATE_ABORTED
Definition: pgbench.c:588
@ CSTATE_PREPARE_THROTTLE
Definition: pgbench.c:513
@ CSTATE_SLEEP
Definition: pgbench.c:542
@ CSTATE_ERROR
Definition: pgbench.c:569

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 453 of file pgbench.c.

455 {
456  ESTATUS_NO_ERROR = 0,
458 
459  /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:460
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:456
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:461
@ ESTATUS_NO_ERROR
Definition: pgbench.c:455
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:459

◆ 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_SYNCPIPELINE 
META_ENDPIPELINE 

Definition at line 686 of file pgbench.c.

688 {
689  META_NONE, /* not a known meta-command */
690  META_SET, /* \set */
691  META_SETSHELL, /* \setshell */
692  META_SHELL, /* \shell */
693  META_SLEEP, /* \sleep */
694  META_GSET, /* \gset */
695  META_ASET, /* \aset */
696  META_IF, /* \if */
697  META_ELIF, /* \elif */
698  META_ELSE, /* \else */
699  META_ENDIF, /* \endif */
700  META_STARTPIPELINE, /* \startpipeline */
701  META_SYNCPIPELINE, /* \syncpipeline */
702  META_ENDPIPELINE, /* \endpipeline */
@ META_ELSE
Definition: pgbench.c:697
@ META_SETSHELL
Definition: pgbench.c:690
@ META_ENDIF
Definition: pgbench.c:698
@ META_SHELL
Definition: pgbench.c:691
@ META_STARTPIPELINE
Definition: pgbench.c:699
@ META_SET
Definition: pgbench.c:689
@ META_ELIF
Definition: pgbench.c:696
@ META_SYNCPIPELINE
Definition: pgbench.c:700
@ META_SLEEP
Definition: pgbench.c:692
@ META_NONE
Definition: pgbench.c:688
@ META_IF
Definition: pgbench.c:695
@ META_ENDPIPELINE
Definition: pgbench.c:701
@ META_ASET
Definition: pgbench.c:694
@ META_GSET
Definition: pgbench.c:693

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 226 of file pgbench.c.

227 {
228  PART_NONE, /* no partitioning */
229  PART_RANGE, /* range partitioning */
230  PART_HASH, /* hash partitioning */
partition_method_t
Definition: pgbench.c:227
@ PART_NONE
Definition: pgbench.c:228
@ PART_RANGE
Definition: pgbench.c:229
@ PART_HASH
Definition: pgbench.c:230

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 704 of file pgbench.c.

706 {
707  QUERY_SIMPLE, /* simple query */
708  QUERY_EXTENDED, /* extended query */
709  QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:708
@ NUM_QUERYMODE
Definition: pgbench.c:709
@ QUERY_SIMPLE
Definition: pgbench.c:706
@ QUERY_EXTENDED
Definition: pgbench.c:707

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 467 of file pgbench.c.

469 {
470  TSTATUS_IDLE,
@ TSTATUS_CONN_ERROR
Definition: pgbench.c:471
@ TSTATUS_IDLE
Definition: pgbench.c:469
@ TSTATUS_IN_BLOCK
Definition: pgbench.c:470
@ TSTATUS_OTHER_ERROR
Definition: pgbench.c:472

Function Documentation

◆ accumStats()

static void accumStats ( StatsData stats,
bool  skipped,
double  lat,
double  lag,
EStatus  estatus,
int64  tries 
)
static

Definition at line 1450 of file pgbench.c.

1453 {
1454  /* Record the skipped transaction */
1455  if (skipped)
1456  {
1457  /* no latency to record on skipped transactions */
1458  stats->skipped++;
1459  return;
1460  }
1461 
1462  /*
1463  * Record the number of retries regardless of whether the transaction was
1464  * successful or failed.
1465  */
1466  if (tries > 1)
1467  {
1468  stats->retries += (tries - 1);
1469  stats->retried++;
1470  }
1471 
1472  switch (estatus)
1473  {
1474  /* Record the successful transaction */
1475  case ESTATUS_NO_ERROR:
1476  stats->cnt++;
1477 
1478  addToSimpleStats(&stats->latency, lat);
1479 
1480  /* and possibly the same for schedule lag */
1481  if (throttle_delay)
1482  addToSimpleStats(&stats->lag, lag);
1483  break;
1484 
1485  /* Record the failed transaction */
1487  stats->serialization_failures++;
1488  break;
1490  stats->deadlock_failures++;
1491  break;
1492  default:
1493  /* internal error which should never occur */
1494  pg_fatal("unexpected error status: %d", estatus);
1495  }
#define pg_fatal(...)
double throttle_delay
Definition: pgbench.c:203
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1402
int64 serialization_failures
Definition: pgbench.c:434
int64 cnt
Definition: pgbench.c:424
int64 retried
Definition: pgbench.c:430
int64 deadlock_failures
Definition: pgbench.c:437
int64 skipped
Definition: pgbench.c:426
SimpleStats lag
Definition: pgbench.c:441
int64 retries
Definition: pgbench.c:428
SimpleStats latency
Definition: pgbench.c:440

References addToSimpleStats(), StatsData::cnt, StatsData::deadlock_failures, ESTATUS_DEADLOCK_ERROR, ESTATUS_NO_ERROR, ESTATUS_SERIALIZATION_ERROR, StatsData::lag, StatsData::latency, pg_fatal, StatsData::retried, StatsData::retries, StatsData::serialization_failures, StatsData::skipped, and throttle_delay.

Referenced by doLog(), and processXactStats().

◆ add_socket_to_set()

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

Definition at line 7878 of file pgbench.c.

7880 {
7881  /* See connect_slot() for background on this code. */
7882 #ifdef WIN32
7883  if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7884  {
7885  pg_log_error("too many concurrent database clients for this platform: %d",
7886  sa->fds.fd_count + 1);
7887  exit(1);
7888  }
7889 #else
7890  if (fd < 0 || fd >= FD_SETSIZE)
7891  {
7892  pg_log_error("socket file descriptor out of range for select(): %d",
7893  fd);
7894  pg_log_error_hint("Try fewer concurrent database clients.");
7895  exit(1);
7896  }
7897 #endif
7898  FD_SET(fd, &sa->fds);
7899  if (fd > sa->maxfd)
7900  sa->maxfd = fd;
exit(1)
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References exit(), fd(), pg_log_error, and pg_log_error_hint.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6192 of file pgbench.c.

6194 {
6195  if (script->commands == NULL || script->commands[0] == NULL)
6196  pg_fatal("empty command list for script \"%s\"", script->desc);
6197 
6198  if (num_scripts >= MAX_SCRIPTS)
6199  pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6200 
6201  CheckConditional(script);
6202 
6203  sql_script[num_scripts] = *script;
6204  num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5854
#define MAX_SCRIPTS
Definition: pgbench.c:346
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:763
static int num_scripts
Definition: pgbench.c:764
const char * desc
Definition: pgbench.c:757
Command ** commands
Definition: pgbench.c:759

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

Referenced by ParseScript().

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1402 of file pgbench.c.

1404 {
1405  if (ss->count == 0 || val < ss->min)
1406  ss->min = val;
1407  if (ss->count == 0 || val > ss->max)
1408  ss->max = val;
1409  ss->count++;
1410  ss->sum += val;
1411  ss->sum2 += val * val;
long val
Definition: informix.c:670
int64 count
Definition: pgbench.c:357
double sum
Definition: pgbench.c:360
double min
Definition: pgbench.c:358
double max
Definition: pgbench.c:359
double sum2
Definition: pgbench.c:361

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

Referenced by accumStats(), and advanceConnectionState().

◆ advanceConnectionState()

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

Definition at line 3588 of file pgbench.c.

3590 {
3591 
3592  /*
3593  * gettimeofday() isn't free, so we get the current timestamp lazily the
3594  * first time it's needed, and reuse the same value throughout this
3595  * function after that. This also ensures that e.g. the calculated
3596  * latency reported in the log file and in the totals are the same. Zero
3597  * means "not set yet". Reset "now" when we execute shell commands or
3598  * expressions, which might take a non-negligible amount of time, though.
3599  */
3600  pg_time_usec_t now = 0;
3601 
3602  /*
3603  * Loop in the state machine, until we have to wait for a result from the
3604  * server or have to sleep for throttling or \sleep.
3605  *
3606  * Note: In the switch-statement below, 'break' will loop back here,
3607  * meaning "continue in the state machine". Return is used to return to
3608  * the caller, giving the thread the opportunity to advance another
3609  * client.
3610  */
3611  for (;;)
3612  {
3613  Command *command;
3614 
3615  switch (st->state)
3616  {
3617  /* Select transaction (script) to run. */
3618  case CSTATE_CHOOSE_SCRIPT:
3619  st->use_file = chooseScript(thread);
3621 
3622  /* reset transaction variables to default values */
3623  st->estatus = ESTATUS_NO_ERROR;
3624  st->tries = 1;
3625 
3626  pg_log_debug("client %d executing script \"%s\"",
3627  st->id, sql_script[st->use_file].desc);
3628 
3629  /*
3630  * If time is over, we're done; otherwise, get ready to start
3631  * a new transaction, or to get throttled if that's requested.
3632  */
3635  break;
3636 
3637  /* Start new transaction (script) */
3638  case CSTATE_START_TX:
3640 
3641  /* establish connection if needed, i.e. under --connect */
3642  if (st->con == NULL)
3643  {
3645 
3646  if ((st->con = doConnect()) == NULL)
3647  {
3648  /*
3649  * as the bench is already running, we do not abort
3650  * the process
3651  */
3652  pg_log_error("client %d aborted while establishing connection", st->id);
3653  st->state = CSTATE_ABORTED;
3654  break;
3655  }
3656 
3657  /* reset now after connection */
3658  now = pg_time_now();
3659 
3660  thread->conn_duration += now - start;
3661 
3662  /* Reset session-local state */
3663  pg_free(st->prepared);
3664  st->prepared = NULL;
3665  }
3666 
3667  /*
3668  * It is the first try to run this transaction. Remember the
3669  * random state: maybe it will get an error and we will need
3670  * to run it again.
3671  */
3672  st->random_state = st->cs_func_rs;
3673 
3674  /* record transaction start time */
3675  st->txn_begin = now;
3676 
3677  /*
3678  * When not throttling, this is also the transaction's
3679  * scheduled start time.
3680  */
3681  if (!throttle_delay)
3682  st->txn_scheduled = now;
3683 
3684  /* Begin with the first command */
3686  st->command = 0;
3687  break;
3688 
3689  /*
3690  * Handle throttling once per transaction by sleeping.
3691  */
3693 
3694  /*
3695  * Generate a delay such that the series of delays will
3696  * approximate a Poisson distribution centered on the
3697  * throttle_delay time.
3698  *
3699  * If transactions are too slow or a given wait is shorter
3700  * than a transaction, the next transaction will start right
3701  * away.
3702  */
3703  Assert(throttle_delay > 0);
3704 
3705  thread->throttle_trigger +=
3707  st->txn_scheduled = thread->throttle_trigger;
3708 
3709  /*
3710  * If --latency-limit is used, and this slot is already late
3711  * so that the transaction will miss the latency limit even if
3712  * it completed immediately, skip this time slot and loop to
3713  * reschedule.
3714  */
3715  if (latency_limit)
3716  {
3718 
3719  if (thread->throttle_trigger < now - latency_limit)
3720  {
3721  processXactStats(thread, st, &now, true, agg);
3722 
3723  /*
3724  * Finish client if -T or -t was exceeded.
3725  *
3726  * Stop counting skipped transactions under -T as soon
3727  * as the timer is exceeded. Because otherwise it can
3728  * take a very long time to count all of them
3729  * especially when quite a lot of them happen with
3730  * unrealistically high rate setting in -R, which
3731  * would prevent pgbench from ending immediately.
3732  * Because of this behavior, note that there is no
3733  * guarantee that all skipped transactions are counted
3734  * under -T though there is under -t. This is OK in
3735  * practice because it's very unlikely to happen with
3736  * realistic setting.
3737  */
3738  if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3739  st->state = CSTATE_FINISHED;
3740 
3741  /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3742  break;
3743  }
3744  }
3745 
3746  /*
3747  * stop client if next transaction is beyond pgbench end of
3748  * execution; otherwise, throttle it.
3749  */
3750  st->state = end_time > 0 && st->txn_scheduled > end_time ?
3752  break;
3753 
3754  /*
3755  * Wait until it's time to start next transaction.
3756  */
3757  case CSTATE_THROTTLE:
3759 
3760  if (now < st->txn_scheduled)
3761  return; /* still sleeping, nothing to do here */
3762 
3763  /* done sleeping, but don't start transaction if we're done */
3765  break;
3766 
3767  /*
3768  * Send a command to server (or execute a meta-command)
3769  */
3770  case CSTATE_START_COMMAND:
3771  command = sql_script[st->use_file].commands[st->command];
3772 
3773  /*
3774  * Transition to script end processing if done, but close up
3775  * shop if a pipeline is open at this point.
3776  */
3777  if (command == NULL)
3778  {
3779  if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3780  st->state = CSTATE_END_TX;
3781  else
3782  {
3783  pg_log_error("client %d aborted: end of script reached with pipeline open",
3784  st->id);
3785  st->state = CSTATE_ABORTED;
3786  }
3787 
3788  break;
3789  }
3790 
3791  /* record begin time of next command, and initiate it */
3792  if (report_per_command)
3793  {
3795  st->stmt_begin = now;
3796  }
3797 
3798  /* Execute the command */
3799  if (command->type == SQL_COMMAND)
3800  {
3801  /* disallow \aset and \gset in pipeline mode */
3802  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
3803  {
3804  if (command->meta == META_GSET)
3805  {
3806  commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3807  st->state = CSTATE_ABORTED;
3808  break;
3809  }
3810  else if (command->meta == META_ASET)
3811  {
3812  commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3813  st->state = CSTATE_ABORTED;
3814  break;
3815  }
3816  }
3817 
3818  if (!sendCommand(st, command))
3819  {
3820  commandFailed(st, "SQL", "SQL command send failed");
3821  st->state = CSTATE_ABORTED;
3822  }
3823  else
3824  {
3825  /* Wait for results, unless in pipeline mode */
3826  if (PQpipelineStatus(st->con) == PQ_PIPELINE_OFF)
3827  st->state = CSTATE_WAIT_RESULT;
3828  else
3829  st->state = CSTATE_END_COMMAND;
3830  }
3831  }
3832  else if (command->type == META_COMMAND)
3833  {
3834  /*-----
3835  * Possible state changes when executing meta commands:
3836  * - on errors CSTATE_ABORTED
3837  * - on sleep CSTATE_SLEEP
3838  * - else CSTATE_END_COMMAND
3839  */
3840  st->state = executeMetaCommand(st, &now);
3841  if (st->state == CSTATE_ABORTED)
3843  }
3844 
3845  /*
3846  * We're now waiting for an SQL command to complete, or
3847  * finished processing a metacommand, or need to sleep, or
3848  * something bad happened.
3849  */
3850  Assert(st->state == CSTATE_WAIT_RESULT ||
3851  st->state == CSTATE_END_COMMAND ||
3852  st->state == CSTATE_SLEEP ||
3853  st->state == CSTATE_ABORTED);
3854  break;
3855 
3856  /*
3857  * non executed conditional branch
3858  */
3859  case CSTATE_SKIP_COMMAND:
3861  /* quickly skip commands until something to do... */
3862  while (true)
3863  {
3864  command = sql_script[st->use_file].commands[st->command];
3865 
3866  /* cannot reach end of script in that state */
3867  Assert(command != NULL);
3868 
3869  /*
3870  * if this is conditional related, update conditional
3871  * state
3872  */
3873  if (command->type == META_COMMAND &&
3874  (command->meta == META_IF ||
3875  command->meta == META_ELIF ||
3876  command->meta == META_ELSE ||
3877  command->meta == META_ENDIF))
3878  {
3879  switch (conditional_stack_peek(st->cstack))
3880  {
3881  case IFSTATE_FALSE:
3882  if (command->meta == META_IF ||
3883  command->meta == META_ELIF)
3884  {
3885  /* we must evaluate the condition */
3887  }
3888  else if (command->meta == META_ELSE)
3889  {
3890  /* we must execute next command */
3894  st->command++;
3895  }
3896  else if (command->meta == META_ENDIF)
3897  {
3900  if (conditional_active(st->cstack))
3902 
3903  /*
3904  * else state remains in
3905  * CSTATE_SKIP_COMMAND
3906  */
3907  st->command++;
3908  }
3909  break;
3910 
3911  case IFSTATE_IGNORED:
3912  case IFSTATE_ELSE_FALSE:
3913  if (command->meta == META_IF)
3915  IFSTATE_IGNORED);
3916  else if (command->meta == META_ENDIF)
3917  {
3920  if (conditional_active(st->cstack))
3922  }
3923  /* could detect "else" & "elif" after "else" */
3924  st->command++;
3925  break;
3926 
3927  case IFSTATE_NONE:
3928  case IFSTATE_TRUE:
3929  case IFSTATE_ELSE_TRUE:
3930  default:
3931 
3932  /*
3933  * inconsistent if inactive, unreachable dead
3934  * code
3935  */
3936  Assert(false);
3937  }
3938  }
3939  else
3940  {
3941  /* skip and consider next */
3942  st->command++;
3943  }
3944 
3945  if (st->state != CSTATE_SKIP_COMMAND)
3946  /* out of quick skip command loop */
3947  break;
3948  }
3949  break;
3950 
3951  /*
3952  * Wait for the current SQL command to complete
3953  */
3954  case CSTATE_WAIT_RESULT:
3955  pg_log_debug("client %d receiving", st->id);
3956 
3957  /*
3958  * Only check for new network data if we processed all data
3959  * fetched prior. Otherwise we end up doing a syscall for each
3960  * individual pipelined query, which has a measurable
3961  * performance impact.
3962  */
3963  if (PQisBusy(st->con) && !PQconsumeInput(st->con))
3964  {
3965  /* there's something wrong */
3966  commandFailed(st, "SQL", "perhaps the backend died while processing");
3967  st->state = CSTATE_ABORTED;
3968  break;
3969  }
3970  if (PQisBusy(st->con))
3971  return; /* don't have the whole result yet */
3972 
3973  /* store or discard the query results */
3974  if (readCommandResponse(st,
3977  {
3978  /*
3979  * outside of pipeline mode: stop reading results.
3980  * pipeline mode: continue reading results until an
3981  * end-of-pipeline response.
3982  */
3983  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
3984  st->state = CSTATE_END_COMMAND;
3985  }
3986  else if (canRetryError(st->estatus))
3987  st->state = CSTATE_ERROR;
3988  else
3989  st->state = CSTATE_ABORTED;
3990  break;
3991 
3992  /*
3993  * Wait until sleep is done. This state is entered after a
3994  * \sleep metacommand. The behavior is similar to
3995  * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
3996  * instead of CSTATE_START_TX.
3997  */
3998  case CSTATE_SLEEP:
4000  if (now < st->sleep_until)
4001  return; /* still sleeping, nothing to do here */
4002  /* Else done sleeping. */
4003  st->state = CSTATE_END_COMMAND;
4004  break;
4005 
4006  /*
4007  * End of command: record stats and proceed to next command.
4008  */
4009  case CSTATE_END_COMMAND:
4010 
4011  /*
4012  * command completed: accumulate per-command execution times
4013  * in thread-local data structure, if per-command latencies
4014  * are requested.
4015  */
4016  if (report_per_command)
4017  {
4019 
4020  command = sql_script[st->use_file].commands[st->command];
4021  /* XXX could use a mutex here, but we choose not to */
4022  addToSimpleStats(&command->stats,
4024  }
4025 
4026  /* Go ahead with next command, to be executed or skipped */
4027  st->command++;
4028  st->state = conditional_active(st->cstack) ?
4030  break;
4031 
4032  /*
4033  * Clean up after an error.
4034  */
4035  case CSTATE_ERROR:
4036  {
4037  TStatus tstatus;
4038 
4040 
4041  /* Clear the conditional stack */
4043 
4044  /* Read and discard until a sync point in pipeline mode */
4045  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4046  {
4047  if (!discardUntilSync(st))
4048  {
4049  st->state = CSTATE_ABORTED;
4050  break;
4051  }
4052  }
4053 
4054  /*
4055  * Check if we have a (failed) transaction block or not,
4056  * and roll it back if any.
4057  */
4058  tstatus = getTransactionStatus(st->con);
4059  if (tstatus == TSTATUS_IN_BLOCK)
4060  {
4061  /* Try to rollback a (failed) transaction block. */
4062  if (!PQsendQuery(st->con, "ROLLBACK"))
4063  {
4064  pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4065  st->id);
4066  st->state = CSTATE_ABORTED;
4067  }
4068  else
4070  }
4071  else if (tstatus == TSTATUS_IDLE)
4072  {
4073  /*
4074  * If time is over, we're done; otherwise, check if we
4075  * can retry the error.
4076  */
4079  }
4080  else
4081  {
4082  if (tstatus == TSTATUS_CONN_ERROR)
4083  pg_log_error("perhaps the backend died while processing");
4084 
4085  pg_log_error("client %d aborted while receiving the transaction status", st->id);
4086  st->state = CSTATE_ABORTED;
4087  }
4088  break;
4089  }
4090 
4091  /*
4092  * Wait for the rollback command to complete
4093  */
4095  {
4096  PGresult *res;
4097 
4098  pg_log_debug("client %d receiving", st->id);
4099  if (!PQconsumeInput(st->con))
4100  {
4101  pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4102  st->id);
4103  st->state = CSTATE_ABORTED;
4104  break;
4105  }
4106  if (PQisBusy(st->con))
4107  return; /* don't have the whole result yet */
4108 
4109  /*
4110  * Read and discard the query result;
4111  */
4112  res = PQgetResult(st->con);
4113  switch (PQresultStatus(res))
4114  {
4115  case PGRES_COMMAND_OK:
4116  /* OK */
4117  PQclear(res);
4118  /* null must be returned */
4119  res = PQgetResult(st->con);
4120  Assert(res == NULL);
4121 
4122  /*
4123  * If time is over, we're done; otherwise, check
4124  * if we can retry the error.
4125  */
4128  break;
4129  default:
4130  pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4131  st->id, PQerrorMessage(st->con));
4132  PQclear(res);
4133  st->state = CSTATE_ABORTED;
4134  break;
4135  }
4136  break;
4137  }
4138 
4139  /*
4140  * Retry the transaction after an error.
4141  */
4142  case CSTATE_RETRY:
4143  command = sql_script[st->use_file].commands[st->command];
4144 
4145  /*
4146  * Inform that the transaction will be retried after the
4147  * error.
4148  */
4149  if (verbose_errors)
4150  printVerboseErrorMessages(st, &now, true);
4151 
4152  /* Count tries and retries */
4153  st->tries++;
4154  command->retries++;
4155 
4156  /*
4157  * Reset the random state as they were at the beginning of the
4158  * transaction.
4159  */
4160  st->cs_func_rs = st->random_state;
4161 
4162  /* Process the first transaction command. */
4163  st->command = 0;
4164  st->estatus = ESTATUS_NO_ERROR;
4166  break;
4167 
4168  /*
4169  * Record a failed transaction.
4170  */
4171  case CSTATE_FAILURE:
4172  command = sql_script[st->use_file].commands[st->command];
4173 
4174  /* Accumulate the failure. */
4175  command->failures++;
4176 
4177  /*
4178  * Inform that the failed transaction will not be retried.
4179  */
4180  if (verbose_errors)
4181  printVerboseErrorMessages(st, &now, false);
4182 
4183  /* End the failed transaction. */
4184  st->state = CSTATE_END_TX;
4185  break;
4186 
4187  /*
4188  * End of transaction (end of script, really).
4189  */
4190  case CSTATE_END_TX:
4191  {
4192  TStatus tstatus;
4193 
4194  /* transaction finished: calculate latency and do log */
4195  processXactStats(thread, st, &now, false, agg);
4196 
4197  /*
4198  * missing \endif... cannot happen if CheckConditional was
4199  * okay
4200  */
4202 
4203  /*
4204  * We must complete all the transaction blocks that were
4205  * started in this script.
4206  */
4207  tstatus = getTransactionStatus(st->con);
4208  if (tstatus == TSTATUS_IN_BLOCK)
4209  {
4210  pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4211  st->id);
4212  st->state = CSTATE_ABORTED;
4213  break;
4214  }
4215  else if (tstatus != TSTATUS_IDLE)
4216  {
4217  if (tstatus == TSTATUS_CONN_ERROR)
4218  pg_log_error("perhaps the backend died while processing");
4219 
4220  pg_log_error("client %d aborted while receiving the transaction status", st->id);
4221  st->state = CSTATE_ABORTED;
4222  break;
4223  }
4224 
4225  if (is_connect)
4226  {
4228 
4230  finishCon(st);
4231  now = pg_time_now();
4232  thread->conn_duration += now - start;
4233  }
4234 
4235  if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4236  {
4237  /* script completed */
4238  st->state = CSTATE_FINISHED;
4239  break;
4240  }
4241 
4242  /* next transaction (script) */
4244 
4245  /*
4246  * Ensure that we always return on this point, so as to
4247  * avoid an infinite loop if the script only contains meta
4248  * commands.
4249  */
4250  return;
4251  }
4252 
4253  /*
4254  * Final states. Close the connection if it's still open.
4255  */
4256  case CSTATE_ABORTED:
4257  case CSTATE_FINISHED:
4258 
4259  /*
4260  * Don't measure the disconnection delays here even if in
4261  * CSTATE_FINISHED and -C/--connect option is specified.
4262  * Because in this case all the connections that this thread
4263  * established are closed at the end of transactions and the
4264  * disconnection delays should have already been measured at
4265  * that moment.
4266  *
4267  * In CSTATE_ABORTED state, the measurement is no longer
4268  * necessary because we cannot report complete results anyways
4269  * in this case.
4270  */
4271  finishCon(st);
4272  return;
4273  }
4274  }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1618
#define Assert(condition)
Definition: c.h:858
ifState conditional_stack_peek(ConditionalStack cstack)
Definition: conditional.c:106
void conditional_stack_push(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:53
bool conditional_stack_pop(ConditionalStack cstack)
Definition: conditional.c:69
bool conditional_active(ConditionalStack cstack)
Definition: conditional.c:140
void conditional_stack_reset(ConditionalStack cstack)
Definition: conditional.c:30
bool conditional_stack_poke(ConditionalStack cstack, ifState new_state)
Definition: conditional.c:118
bool conditional_stack_empty(ConditionalStack cstack)
Definition: conditional.c:130
@ IFSTATE_FALSE
Definition: conditional.h:34
@ IFSTATE_ELSE_TRUE
Definition: conditional.h:40
@ IFSTATE_IGNORED
Definition: conditional.h:37
@ IFSTATE_TRUE
Definition: conditional.h:32
@ IFSTATE_NONE
Definition: conditional.h:31
@ IFSTATE_ELSE_FALSE
Definition: conditional.h:42
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7147
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:7189
ExecStatusType PQresultStatus(const PGresult *res)
Definition: fe-exec.c:3411
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1984
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1416
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2031
PGresult * PQgetResult(PGconn *conn)
Definition: fe-exec.c:2062
void pg_free(void *ptr)
Definition: fe_memutils.c:105
return str start
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:100
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:162
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:163
#define pg_log_debug(...)
Definition: logging.h:133
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:850
static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
Definition: pgbench.c:3550
int64 latency_limit
Definition: pgbench.c:211
static TStatus getTransactionStatus(PGconn *con)
Definition: pgbench.c:3513
int64 end_time
Definition: pgbench.c:175
static bool doRetry(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3427
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:3154
TStatus
Definition: pgbench.c:468
static void finishCon(CState *st)
Definition: pgbench.c:7694
int64 pg_time_usec_t
Definition: pgbench.c:369
bool is_connect
Definition: pgbench.c:265
int nxacts
Definition: pgbench.c:173
bool report_per_command
Definition: pgbench.c:266
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:866
static int discardUntilSync(CState *st)
Definition: pgbench.c:3473
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:4284
static bool canRetryError(EStatus estatus)
Definition: pgbench.c:3224
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:3027
static int chooseScript(TState *thread)
Definition: pgbench.c:3046
#define SQL_COMMAND
Definition: pgbench.c:677
volatile sig_atomic_t timer_exceeded
Definition: pgbench.c:303
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:4665
int duration
Definition: pgbench.c:174
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:860
static bool verbose_errors
Definition: pgbench.c:767
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1178
static PGconn * doConnect(void)
Definition: pgbench.c:1530
#define META_COMMAND
Definition: pgbench.c:678
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:3240
int64 cnt
Definition: pgbench.c:636
int id
Definition: pgbench.c:598
pg_time_usec_t txn_scheduled
Definition: pgbench.c:616
pg_time_usec_t stmt_begin
Definition: pgbench.c:619
int command
Definition: pgbench.c:609
int use_file
Definition: pgbench.c:608
ConditionalStack cstack
Definition: pgbench.c:600
pg_prng_state random_state
Definition: pgbench.c:631
pg_time_usec_t txn_begin
Definition: pgbench.c:618
EStatus estatus
Definition: pgbench.c:628
PGconn * con
Definition: pgbench.c:597
pg_prng_state cs_func_rs
Definition: pgbench.c:606
uint32 tries
Definition: pgbench.c:632
bool ** prepared
Definition: pgbench.c:622
ConnectionStateEnum state
Definition: pgbench.c:599
int64 retries
Definition: pgbench.c:751
char * varprefix
Definition: pgbench.c:748
int type
Definition: pgbench.c:743
MetaCommand meta
Definition: pgbench.c:744
SimpleStats stats
Definition: pgbench.c:750
int64 failures
Definition: pgbench.c:752
int64 throttle_trigger
Definition: pgbench.c:660
pg_prng_state ts_throttle_rs
Definition: pgbench.c:657
pg_time_usec_t conn_duration
Definition: pgbench.c:667

References addToSimpleStats(), Assert, canRetryError(), 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(), conditional_stack_reset(), TState::conn_duration, CState::cs_func_rs, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_ERROR, CSTATE_FAILURE, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_RETRY, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, ParsedScript::desc, discardUntilSync(), doConnect(), doRetry(), duration, end_time, CState::estatus, ESTATUS_META_COMMAND_ERROR, ESTATUS_NO_ERROR, executeMetaCommand(), Command::failures, finishCon(), getPoissonRand(), getTransactionStatus(), 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_free(), pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PGRES_COMMAND_OK, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQclear(), PQconsumeInput(), PQerrorMessage(), PQgetResult(), PQisBusy(), PQpipelineStatus(), PQresultStatus(), PQsendQuery(), CState::prepared, printVerboseErrorMessages(), processXactStats(), CState::random_state, readCommandResponse(), report_per_command, res, Command::retries, sendCommand(), SQL_COMMAND, sql_script, start, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, CState::tries, TState::ts_throttle_rs, TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, Command::varprefix, and verbose_errors.

Referenced by threadRun().

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7859 of file pgbench.c.

7861 {
7862  return (socket_set *) pg_malloc0(sizeof(socket_set));
void * pg_malloc0(size_t size)
Definition: fe_memutils.c:53

References pg_malloc0().

Referenced by threadRun().

◆ allocCStatePrepared()

static void allocCStatePrepared ( CState st)
static

Definition at line 3068 of file pgbench.c.

3070 {
3071  Assert(st->prepared == NULL);
3072 
3073  st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3074  for (int i = 0; i < num_scripts; i++)
3075  {
3076  ParsedScript *script = &sql_script[i];
3077  int numcmds;
3078 
3079  for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3080  ;
3081  st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3082  }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int i
Definition: isn.c:73

References Assert, ParsedScript::commands, i, num_scripts, pg_malloc(), pg_malloc0(), CState::prepared, and sql_script.

Referenced by prepareCommand(), and prepareCommandsInPipeline().

◆ assignVariables()

static char* assignVariables ( Variables variables,
char *  sql 
)
static

Definition at line 1935 of file pgbench.c.

1937 {
1938  char *p,
1939  *name,
1940  *val;
1941 
1942  p = sql;
1943  while ((p = strchr(p, ':')) != NULL)
1944  {
1945  int eaten;
1946 
1947  name = parseVariable(p, &eaten);
1948  if (name == NULL)
1949  {
1950  while (*p == ':')
1951  {
1952  p++;
1953  }
1954  continue;
1955  }
1956 
1957  val = getVariable(variables, name);
1958  free(name);
1959  if (val == NULL)
1960  {
1961  p++;
1962  continue;
1963  }
1964 
1965  p = replaceVariable(&sql, p, eaten, val);
1966  }
1967 
1968  return sql;
#define free(a)
Definition: header.h:65
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1630
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1888
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1915
const char * name

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3224 of file pgbench.c.

3226 {
3227  return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3228  estatus == ESTATUS_DEADLOCK_ERROR);

References ESTATUS_DEADLOCK_ERROR, and ESTATUS_SERIALIZATION_ERROR.

Referenced by advanceConnectionState(), doRetry(), and readCommandResponse().

◆ CheckConditional()

static void CheckConditional ( const ParsedScript ps)
static

Definition at line 5854 of file pgbench.c.

5856 {
5857  /* statically check conditional structure */
5859  int i;
5860 
5861  for (i = 0; ps->commands[i] != NULL; i++)
5862  {
5863  Command *cmd = ps->commands[i];
5864 
5865  if (cmd->type == META_COMMAND)
5866  {
5867  switch (cmd->meta)
5868  {
5869  case META_IF:
5871  break;
5872  case META_ELIF:
5873  if (conditional_stack_empty(cs))
5874  ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5876  ConditionError(ps->desc, i + 1, "\\elif after \\else");
5877  break;
5878  case META_ELSE:
5879  if (conditional_stack_empty(cs))
5880  ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5882  ConditionError(ps->desc, i + 1, "\\else after \\else");
5884  break;
5885  case META_ENDIF:
5886  if (!conditional_stack_pop(cs))
5887  ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5888  break;
5889  default:
5890  /* ignore anything else... */
5891  break;
5892  }
5893  }
5894  }
5895  if (!conditional_stack_empty(cs))
5896  ConditionError(ps->desc, i + 1, "\\if without matching \\endif");
ConditionalStack conditional_stack_create(void)
Definition: conditional.c:18
void conditional_stack_destroy(ConditionalStack cstack)
Definition: conditional.c:43
struct parser_state ps
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5844

References conditional_stack_create(), conditional_stack_destroy(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), ConditionError(), i, IFSTATE_ELSE_FALSE, IFSTATE_FALSE, Command::meta, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_IF, ps, and Command::type.

Referenced by addScript().

◆ checkInitSteps()

static void checkInitSteps ( const char *  initialize_steps)
static

Definition at line 5202 of file pgbench.c.

5204 {
5205  if (initialize_steps[0] == '\0')
5206  pg_fatal("no initialization steps specified");
5207 
5208  for (const char *step = initialize_steps; *step != '\0'; step++)
5209  {
5210  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5211  {
5212  pg_log_error("unrecognized initialization step \"%c\"", *step);
5213  pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5214  exit(1);
5215  }
5216  }
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:163

References ALL_INIT_STEPS, exit(), pg_fatal, pg_log_error, and pg_log_error_detail.

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3046 of file pgbench.c.

3048 {
3049  int i = 0;
3050  int64 w;
3051 
3052  if (num_scripts == 1)
3053  return 0;
3054 
3055  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3056  do
3057  {
3058  w -= sql_script[i++].weight;
3059  } while (w >= 0);
3060 
3061  return i - 1;
static int64 total_weight
Definition: pgbench.c:765
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1101
int weight
Definition: pgbench.c:758
pg_prng_state ts_choose_rs
Definition: pgbench.c:656

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

Referenced by advanceConnectionState().

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 7871 of file pgbench.c.

7873 {
7874  FD_ZERO(&sa->fds);
7875  sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 2003 of file pgbench.c.

2005 {
2006  if (pval->type == PGBT_BOOLEAN)
2007  {
2008  *bval = pval->u.bval;
2009  return true;
2010  }
2011  else /* NULL, INT or DOUBLE */
2012  {
2013  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2014  *bval = false; /* suppress uninitialized-variable warnings */
2015  return false;
2016  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1981
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@36 u

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

Referenced by evalLazyFunc(), and evalStandardFunc().

◆ coerceToDouble()

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

Definition at line 2072 of file pgbench.c.

2074 {
2075  if (pval->type == PGBT_DOUBLE)
2076  {
2077  *dval = pval->u.dval;
2078  return true;
2079  }
2080  else if (pval->type == PGBT_INT)
2081  {
2082  *dval = (double) pval->u.ival;
2083  return true;
2084  }
2085  else /* BOOLEAN or NULL */
2086  {
2087  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2088  return false;
2089  }
@ PGBT_INT
Definition: pgbench.h:38
@ PGBT_DOUBLE
Definition: pgbench.h:39
int64 ival
Definition: pgbench.h:49
double dval
Definition: pgbench.h:50

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

Referenced by evalStandardFunc().

◆ coerceToInt()

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

Definition at line 2044 of file pgbench.c.

2046 {
2047  if (pval->type == PGBT_INT)
2048  {
2049  *ival = pval->u.ival;
2050  return true;
2051  }
2052  else if (pval->type == PGBT_DOUBLE)
2053  {
2054  double dval = rint(pval->u.dval);
2055 
2056  if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2057  {
2058  pg_log_error("double to int overflow for %f", dval);
2059  return false;
2060  }
2061  *ival = (int64) dval;
2062  return true;
2063  }
2064  else /* BOOLEAN or NULL */
2065  {
2066  pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2067  return false;
2068  }
#define FLOAT8_FITS_IN_INT64(num)
Definition: c.h:1092

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

◆ commandError()

static void commandError ( CState st,
const char *  message 
)
static

Definition at line 3037 of file pgbench.c.

3039 {
3041  pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3042  st->id, st->command, st->use_file, message);
#define pg_log_info(...)
Definition: logging.h:124

References Assert, CState::command, ParsedScript::commands, CState::id, pg_log_info, SQL_COMMAND, sql_script, Command::type, and CState::use_file.

Referenced by readCommandResponse().

◆ commandFailed()

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

Definition at line 3027 of file pgbench.c.

3029 {
3030  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3031  st->id, st->command, cmd, st->use_file, message);

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

Referenced by advanceConnectionState(), and executeMetaCommand().

◆ compareVariableNames()

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

Definition at line 1595 of file pgbench.c.

1597 {
1598  return strcmp(((const Variable *) v1)->name,
1599  ((const Variable *) v2)->name);

References name.

Referenced by lookupVariable().

◆ computeIterativeZipfian()

static int64 computeIterativeZipfian ( pg_prng_state state,
int64  n,
double  s 
)
static

Definition at line 1200 of file pgbench.c.

1202 {
1203  double b = pow(2.0, s - 1.0);
1204  double x,
1205  t,
1206  u,
1207  v;
1208 
1209  /* Ensure n is sane */
1210  if (n <= 1)
1211  return 1;
1212 
1213  while (true)
1214  {
1215  /* random variates */
1216  u = pg_prng_double(state);
1217  v = pg_prng_double(state);
1218 
1219  x = floor(pow(u, -1.0 / (s - 1.0)));
1220 
1221  t = pow(1.0 + 1.0 / x, s - 1.0);
1222  /* reject if too large or out of bound */
1223  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1224  break;
1225  }
1226  return (int64) x;
int b
Definition: isn.c:70
int x
Definition: isn.c:71
double pg_prng_double(pg_prng_state *state)
Definition: pg_prng.c:268
Definition: regguts.h:323

References b, pg_prng_double(), and x.

Referenced by getZipfianRand().

◆ ConditionError()

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

Definition at line 5844 of file pgbench.c.

5846 {
5847  pg_fatal("condition error in script \"%s\" command %d: %s",
5848  desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

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

Definition at line 5548 of file pgbench.c.

5550 {
5551  Command *my_command;
5552  char *p = skip_sql_comments(buf->data);
5553 
5554  if (p == NULL)
5555  return NULL;
5556 
5557  /* Allocate and initialize Command structure */
5558  my_command = (Command *) pg_malloc(sizeof(Command));
5559  initPQExpBuffer(&my_command->lines);
5560  appendPQExpBufferStr(&my_command->lines, p);
5561  my_command->first_line = NULL; /* this is set later */
5562  my_command->type = SQL_COMMAND;
5563  my_command->meta = META_NONE;
5564  my_command->argc = 0;
5565  my_command->retries = 0;
5566  my_command->failures = 0;
5567  memset(my_command->argv, 0, sizeof(my_command->argv));
5568  my_command->varprefix = NULL; /* allocated later, if needed */
5569  my_command->expr = NULL;
5570  initSimpleStats(&my_command->stats);
5571  my_command->prepname = NULL; /* set later, if needed */
5572 
5573  return my_command;
static char * buf
Definition: pg_test_fsync.c:73
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5513
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1393
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:741
PgBenchExpr * expr
Definition: pgbench.c:749
char * argv[MAX_ARGS]
Definition: pgbench.c:746
char * first_line
Definition: pgbench.c:742
int argc
Definition: pgbench.c:745
char * prepname
Definition: pgbench.c:747

References appendPQExpBufferStr(), Command::argc, Command::argv, buf, Command::expr, Command::failures, Command::first_line, initPQExpBuffer(), initSimpleStats(), Command::lines, Command::meta, META_NONE, pg_malloc(), Command::prepname, Command::retries, skip_sql_comments(), SQL_COMMAND, Command::stats, Command::type, and Command::varprefix.

Referenced by ParseScript().

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 4738 of file pgbench.c.

4740 {
4741  PQExpBufferData query;
4742 
4743  /* we must have to create some partitions */
4744  Assert(partitions > 0);
4745 
4746  fprintf(stderr, "creating %d partitions...\n", partitions);
4747 
4748  initPQExpBuffer(&query);
4749 
4750  for (int p = 1; p <= partitions; p++)
4751  {
4753  {
4754  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4755 
4756  printfPQExpBuffer(&query,
4757  "create%s table pgbench_accounts_%d\n"
4758  " partition of pgbench_accounts\n"
4759  " for values from (",
4760  unlogged_tables ? " unlogged" : "", p);
4761 
4762  /*
4763  * For RANGE, we use open-ended partitions at the beginning and
4764  * end to allow any valid value for the primary key. Although the
4765  * actual minimum and maximum values can be derived from the
4766  * scale, it is more generic and the performance is better.
4767  */
4768  if (p == 1)
4769  appendPQExpBufferStr(&query, "minvalue");
4770  else
4771  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4772 
4773  appendPQExpBufferStr(&query, ") to (");
4774 
4775  if (p < partitions)
4776  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4777  else
4778  appendPQExpBufferStr(&query, "maxvalue");
4779 
4780  appendPQExpBufferChar(&query, ')');
4781  }
4782  else if (partition_method == PART_HASH)
4783  printfPQExpBuffer(&query,
4784  "create%s table pgbench_accounts_%d\n"
4785  " partition of pgbench_accounts\n"
4786  " for values with (modulus %d, remainder %d)",
4787  unlogged_tables ? " unlogged" : "", p,
4788  partitions, p - 1);
4789  else /* cannot get there */
4790  Assert(0);
4791 
4792  /*
4793  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4794  * pgbench_accounts.
4795  */
4796  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4797 
4798  executeStatement(con, query.data);
4799  }
4800 
4801  termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:548
int scale
Definition: pgbench.c:181
static int partitions
Definition: pgbench.c:223
int fillfactor
Definition: pgbench.c:187
static partition_method_t partition_method
Definition: pgbench.c:233
bool unlogged_tables
Definition: pgbench.c:192
#define naccounts
Definition: pgbench.c:245
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1499
#define fprintf
Definition: port.h:242
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

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

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3473 of file pgbench.c.

3475 {
3476  /* send a sync */
3477  if (!PQpipelineSync(st->con))
3478  {
3479  pg_log_error("client %d aborted: failed to send a pipeline sync",
3480  st->id);
3481  return 0;
3482  }
3483 
3484  /* receive PGRES_PIPELINE_SYNC and null following it */
3485  for (;;)
3486  {
3487  PGresult *res = PQgetResult(st->con);
3488 
3490  {
3491  PQclear(res);
3492  res = PQgetResult(st->con);
3493  Assert(res == NULL);
3494  break;
3495  }
3496  PQclear(res);
3497  }
3498 
3499  /* exit pipeline */
3500  if (PQexitPipelineMode(st->con) != 1)
3501  {
3502  pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3503  st->id);
3504  return 0;
3505  }
3506  return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3073
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3272
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:114

References Assert, CState::con, CState::id, pg_log_error, PGRES_PIPELINE_SYNC, PQclear(), PQexitPipelineMode(), PQgetResult(), PQpipelineSync(), PQresultStatus(), and res.

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4704 of file pgbench.c.

4706 {
4707  int i;
4708 
4709  for (i = 0; i < length; i++)
4710  finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1530 of file pgbench.c.

1532 {
1533  PGconn *conn;
1534  bool new_pass;
1535  static char *password = NULL;
1536 
1537  /*
1538  * Start the connection. Loop until we have a password if requested by
1539  * backend.
1540  */
1541  do
1542  {
1543 #define PARAMS_ARRAY_SIZE 7
1544 
1545  const char *keywords[PARAMS_ARRAY_SIZE];
1546  const char *values[PARAMS_ARRAY_SIZE];
1547 
1548  keywords[0] = "host";
1549  values[0] = pghost;
1550  keywords[1] = "port";
1551  values[1] = pgport;
1552  keywords[2] = "user";
1553  values[2] = username;
1554  keywords[3] = "password";
1555  values[3] = password;
1556  keywords[4] = "dbname";
1557  values[4] = dbName;
1558  keywords[5] = "fallback_application_name";
1559  values[5] = progname;
1560  keywords[6] = NULL;
1561  values[6] = NULL;
1562 
1563  new_pass = false;
1564 
1565  conn = PQconnectdbParams(keywords, values, true);
1566 
1567  if (!conn)
1568  {
1569  pg_log_error("connection to database \"%s\" failed", dbName);
1570  return NULL;
1571  }
1572 
1573  if (PQstatus(conn) == CONNECTION_BAD &&
1575  !password)
1576  {
1577  PQfinish(conn);
1578  password = simple_prompt("Password: ", false);
1579  new_pass = true;
1580  }
1581  } while (new_pass);
1582 
1583  /* check to see that the backend connection was successfully made */
1584  if (PQstatus(conn) == CONNECTION_BAD)
1585  {
1587  PQfinish(conn);
1588  return NULL;
1589  }
1590 
1591  return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:152
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:689
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7198
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7094
void PQfinish(PGconn *conn)
Definition: fe-connect.c:4868
@ CONNECTION_BAD
Definition: libpq-fe.h:62
#define PARAMS_ARRAY_SIZE
const char * pghost
Definition: pgbench.c:294
const char * username
Definition: pgbench.c:296
const char * progname
Definition: pgbench.c:299
const char * pgport
Definition: pgbench.c:295
const char * dbName
Definition: pgbench.c:297
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:54
PGconn * conn
Definition: streamutil.c:55

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

◆ doLog()

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

Definition at line 4545 of file pgbench.c.

4548 {
4549  FILE *logfile = thread->logfile;
4551 
4552  Assert(use_log);
4553 
4554  /*
4555  * Skip the log entry if sampling is enabled and this row doesn't belong
4556  * to the random sample.
4557  */
4558  if (sample_rate != 0.0 &&
4560  return;
4561 
4562  /* should we aggregate the results or not? */
4563  if (agg_interval > 0)
4564  {
4566 
4567  /*
4568  * Loop until we reach the interval of the current moment, and print
4569  * any empty intervals in between (this may happen with very low tps,
4570  * e.g. --rate=0.1).
4571  */
4572 
4573  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4574  {
4575  double lag_sum = 0.0;
4576  double lag_sum2 = 0.0;
4577  double lag_min = 0.0;
4578  double lag_max = 0.0;
4579  int64 skipped = 0;
4580  int64 serialization_failures = 0;
4581  int64 deadlock_failures = 0;
4582  int64 retried = 0;
4583  int64 retries = 0;
4584 
4585  /* print aggregated report to logfile */
4586  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4587  agg->start_time / 1000000, /* seconds since Unix epoch */
4588  agg->cnt,
4589  agg->latency.sum,
4590  agg->latency.sum2,
4591  agg->latency.min,
4592  agg->latency.max);
4593 
4594  if (throttle_delay)
4595  {
4596  lag_sum = agg->lag.sum;
4597  lag_sum2 = agg->lag.sum2;
4598  lag_min = agg->lag.min;
4599  lag_max = agg->lag.max;
4600  }
4601  fprintf(logfile, " %.0f %.0f %.0f %.0f",
4602  lag_sum,
4603  lag_sum2,
4604  lag_min,
4605  lag_max);
4606 
4607  if (latency_limit)
4608  skipped = agg->skipped;
4609  fprintf(logfile, " " INT64_FORMAT, skipped);
4610 
4611  if (max_tries != 1)
4612  {
4613  retried = agg->retried;
4614  retries = agg->retries;
4615  }
4616  fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4617 
4618  if (failures_detailed)
4619  {
4620  serialization_failures = agg->serialization_failures;
4621  deadlock_failures = agg->deadlock_failures;
4622  }
4624  serialization_failures,
4625  deadlock_failures);
4626 
4627  fputc('\n', logfile);
4628 
4629  /* reset data and move to next interval */
4630  initStats(agg, next);
4631  }
4632 
4633  /* accumulate the current transaction */
4634  accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4635  }
4636  else
4637  {
4638  /* no, print raw transactions */
4639  if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4640  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4641  INT64_FORMAT,
4642  st->id, st->cnt, latency, st->use_file,
4643  now / 1000000, now % 1000000);
4644  else
4645  fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4646  INT64_FORMAT,
4647  st->id, st->cnt, getResultString(skipped, st->estatus),
4648  st->use_file, now / 1000000, now % 1000000);
4649 
4650  if (throttle_delay)
4651  fprintf(logfile, " %.0f", lag);
4652  if (max_tries != 1)
4653  fprintf(logfile, " %u", st->tries - 1);
4654  fputc('\n', logfile);
4655  }
static int32 next
Definition: blutils.c:221
static FILE * logfile
Definition: pg_regress.c:127
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1450
uint32 max_tries
Definition: pgbench.c:289
bool use_log
Definition: pgbench.c:256
int agg_interval
Definition: pgbench.c:258
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4514
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1433
double sample_rate
Definition: pgbench.c:197
bool failures_detailed
Definition: pgbench.c:291
pg_time_usec_t epoch_shift
Definition: pgbench.c:448
pg_time_usec_t start_time
Definition: pgbench.c:377
FILE * logfile
Definition: pgbench.c:661
pg_prng_state ts_sample_rs
Definition: pgbench.c:658

References accumStats(), agg_interval, Assert, StatsData::cnt, CState::cnt, StatsData::deadlock_failures, epoch_shift, CState::estatus, ESTATUS_NO_ERROR, failures_detailed, fprintf, getResultString(), CState::id, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, latency_limit, TState::logfile, logfile, SimpleStats::max, max_tries, SimpleStats::min, next, now(), pg_prng_double(), pg_time_now(), StatsData::retried, StatsData::retries, sample_rate, StatsData::serialization_failures, StatsData::skipped, StatsData::start_time, SimpleStats::sum, SimpleStats::sum2, throttle_delay, CState::tries, TState::ts_sample_rs, CState::use_file, and use_log.

Referenced by processXactStats(), and threadRun().

◆ doRetry()

static bool doRetry ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3427 of file pgbench.c.

3429 {
3431 
3432  /* We can only retry serialization or deadlock errors. */
3433  if (!canRetryError(st->estatus))
3434  return false;
3435 
3436  /*
3437  * We must have at least one option to limit the retrying of transactions
3438  * that got an error.
3439  */
3441 
3442  /*
3443  * We cannot retry the error if we have reached the maximum number of
3444  * tries.
3445  */
3446  if (max_tries && st->tries >= max_tries)
3447  return false;
3448 
3449  /*
3450  * We cannot retry the error if we spent too much time on this
3451  * transaction.
3452  */
3453  if (latency_limit)
3454  {
3456  if (*now - st->txn_scheduled > latency_limit)
3457  return false;
3458  }
3459 
3460  /*
3461  * We cannot retry the error if the benchmark duration is over.
3462  */
3463  if (timer_exceeded)
3464  return false;
3465 
3466  /* OK */
3467  return true;

References Assert, canRetryError(), duration, CState::estatus, ESTATUS_NO_ERROR, latency_limit, max_tries, now(), pg_time_now_lazy(), timer_exceeded, CState::tries, and CState::txn_scheduled.

Referenced by advanceConnectionState().

◆ enlargeVariables()

static void enlargeVariables ( Variables variables,
int  needed 
)
static

Definition at line 1772 of file pgbench.c.

1774 {
1775  /* total number of variables required now */
1776  needed += variables->nvars;
1777 
1778  if (variables->max_vars < needed)
1779  {
1780  variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1781  variables->vars = (Variable *)
1782  pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1783  }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:309
Variable * vars
Definition: pgbench.c:333
int nvars
Definition: pgbench.c:334
int max_vars
Definition: pgbench.c:341

References Variables::max_vars, Variables::nvars, pg_realloc(), VARIABLES_ALLOC_MARGIN, and Variables::vars.

Referenced by lookupCreateVariable().

◆ evalFunc()

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

Definition at line 2820 of file pgbench.c.

2823 {
2824  if (isLazyFunc(func))
2825  return evalLazyFunc(st, func, args, retval);
2826  else
2827  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2124
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2131
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2248

References generate_unaccent_rules::args, evalLazyFunc(), evalStandardFunc(), and isLazyFunc().

Referenced by evaluateExpr().

◆ evalLazyFunc()

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

Definition at line 2131 of file pgbench.c.

2134 {
2135  PgBenchValue a1,
2136  a2;
2137  bool ba1,
2138  ba2;
2139 
2140  Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
2141 
2142  /* args points to first condition */
2143  if (!evaluateExpr(st, args->expr, &a1))
2144  return false;
2145 
2146  /* second condition for AND/OR and corresponding branch for CASE */
2147  args = args->next;
2148 
2149  switch (func)
2150  {
2151  case PGBENCH_AND:
2152  if (a1.type == PGBT_NULL)
2153  {
2154  setNullValue(retval);
2155  return true;
2156  }
2157 
2158  if (!coerceToBool(&a1, &ba1))
2159  return false;
2160 
2161  if (!ba1)
2162  {
2163  setBoolValue(retval, false);
2164  return true;
2165  }
2166 
2167  if (!evaluateExpr(st, args->expr, &a2))
2168  return false;
2169 
2170  if (a2.type == PGBT_NULL)
2171  {
2172  setNullValue(retval);
2173  return true;
2174  }
2175  else if (!coerceToBool(&a2, &ba2))
2176  return false;
2177  else
2178  {
2179  setBoolValue(retval, ba2);
2180  return true;
2181  }
2182 
2183  return true;
2184 
2185  case PGBENCH_OR:
2186 
2187  if (a1.type == PGBT_NULL)
2188  {
2189  setNullValue(retval);
2190  return true;
2191  }
2192 
2193  if (!coerceToBool(&a1, &ba1))
2194  return false;
2195 
2196  if (ba1)
2197  {
2198  setBoolValue(retval, true);
2199  return true;
2200  }
2201 
2202  if (!evaluateExpr(st, args->expr, &a2))
2203  return false;
2204 
2205  if (a2.type == PGBT_NULL)
2206  {
2207  setNullValue(retval);
2208  return true;
2209  }
2210  else if (!coerceToBool(&a2, &ba2))
2211  return false;
2212  else
2213  {
2214  setBoolValue(retval, ba2);
2215  return true;
2216  }
2217 
2218  case PGBENCH_CASE:
2219  /* when true, execute branch */
2220  if (valueTruth(&a1))
2221  return evaluateExpr(st, args->expr, retval);
2222 
2223  /* now args contains next condition or final else expression */
2224  args = args->next;
2225 
2226  /* final else case? */
2227  if (args->next == NULL)
2228  return evaluateExpr(st, args->expr, retval);
2229 
2230  /* no, another when, proceed */
2231  return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2232 
2233  default:
2234  /* internal error, cannot get here */
2235  Assert(0);
2236  break;
2237  }
2238  return false;
static const FormData_pg_attribute a1
Definition: heap.c:142
static const FormData_pg_attribute a2
Definition: heap.c:156
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:2093
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2836
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:2101
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:2023
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:2003
@ PGBT_NULL
Definition: pgbench.h:37
@ PGBENCH_AND
Definition: pgbench.h:87
@ PGBENCH_OR
Definition: pgbench.h:88
@ PGBENCH_CASE
Definition: pgbench.h:100

References a1, a2, generate_unaccent_rules::args, Assert, coerceToBool(), evaluateExpr(), isLazyFunc(), PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), and valueTruth().

Referenced by evalFunc().

◆ evalStandardFunc()

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

Definition at line 2248 of file pgbench.c.

2252 {
2253  /* evaluate all function arguments */
2254  int nargs = 0;
2255  PgBenchExprLink *l = args;
2256  bool has_null = false;
2257 
2258  /*
2259  * This value is double braced to workaround GCC bug 53119, which seems to
2260  * exist at least on gcc (Debian 4.7.2-5) 4.7.2, 32-bit.
2261  */
2262  PgBenchValue vargs[MAX_FARGS] = {{0}};
2263 
2264  for (nargs = 0; nargs < MAX_FARGS && l != NULL; nargs++, l = l->next)
2265  {
2266  if (!evaluateExpr(st, l->expr, &vargs[nargs]))
2267  return false;
2268  has_null |= vargs[nargs].type == PGBT_NULL;
2269  }
2270 
2271  if (l != NULL)
2272  {
2273  pg_log_error("too many function arguments, maximum is %d", MAX_FARGS);
2274  return false;
2275  }
2276 
2277  /* NULL arguments */
2278  if (has_null && func != PGBENCH_IS && func != PGBENCH_DEBUG)
2279  {
2280  setNullValue(retval);
2281  return true;
2282  }
2283 
2284  /* then evaluate function */
2285  switch (func)
2286  {
2287  /* overloaded operators */
2288  case PGBENCH_ADD:
2289  case PGBENCH_SUB:
2290  case PGBENCH_MUL:
2291  case PGBENCH_DIV:
2292  case PGBENCH_MOD:
2293  case PGBENCH_EQ:
2294  case PGBENCH_NE:
2295  case PGBENCH_LE:
2296  case PGBENCH_LT:
2297  {
2298  PgBenchValue *lval = &vargs[0],
2299  *rval = &vargs[1];
2300 
2301  Assert(nargs == 2);
2302 
2303  /* overloaded type management, double if some double */
2304  if ((lval->type == PGBT_DOUBLE ||
2305  rval->type == PGBT_DOUBLE) && func != PGBENCH_MOD)
2306  {
2307  double ld,
2308  rd;
2309 
2310  if (!coerceToDouble(lval, &ld) ||
2311  !coerceToDouble(rval, &rd))
2312  return false;
2313 
2314  switch (func)
2315  {
2316  case PGBENCH_ADD:
2317  setDoubleValue(retval, ld + rd);
2318  return true;
2319 
2320  case PGBENCH_SUB:
2321  setDoubleValue(retval, ld - rd);
2322  return true;
2323 
2324  case PGBENCH_MUL:
2325  setDoubleValue(retval, ld * rd);
2326  return true;
2327 
2328  case PGBENCH_DIV:
2329  setDoubleValue(retval, ld / rd);
2330  return true;
2331 
2332  case PGBENCH_EQ:
2333  setBoolValue(retval, ld == rd);
2334  return true;
2335 
2336  case PGBENCH_NE:
2337  setBoolValue(retval, ld != rd);
2338  return true;
2339 
2340  case PGBENCH_LE:
2341  setBoolValue(retval, ld <= rd);
2342  return true;
2343 
2344  case PGBENCH_LT:
2345  setBoolValue(retval, ld < rd);
2346  return true;
2347 
2348  default:
2349  /* cannot get here */
2350  Assert(0);
2351  }
2352  }
2353  else /* we have integer operands, or % */
2354  {
2355  int64 li,
2356  ri,
2357  res;
2358 
2359  if (!coerceToInt(lval, &li) ||
2360  !coerceToInt(rval, &ri))
2361  return false;
2362 
2363  switch (func)
2364  {
2365  case PGBENCH_ADD:
2366  if (pg_add_s64_overflow(li, ri, &res))
2367  {
2368  pg_log_error("bigint add out of range");
2369  return false;
2370  }
2371  setIntValue(retval, res);
2372  return true;
2373 
2374  case PGBENCH_SUB:
2375  if (pg_sub_s64_overflow(li, ri, &res))
2376  {
2377  pg_log_error("bigint sub out of range");
2378  return false;
2379  }
2380  setIntValue(retval, res);
2381  return true;
2382 
2383  case PGBENCH_MUL:
2384  if (pg_mul_s64_overflow(li, ri, &res))
2385  {
2386  pg_log_error("bigint mul out of range");
2387  return false;
2388  }
2389  setIntValue(retval, res);
2390  return true;
2391 
2392  case PGBENCH_EQ:
2393  setBoolValue(retval, li == ri);
2394  return true;
2395 
2396  case PGBENCH_NE:
2397  setBoolValue(retval, li != ri);
2398  return true;
2399 
2400  case PGBENCH_LE:
2401  setBoolValue(retval, li <= ri);
2402  return true;
2403 
2404  case PGBENCH_LT:
2405  setBoolValue(retval, li < ri);
2406  return true;
2407 
2408  case PGBENCH_DIV:
2409  case PGBENCH_MOD:
2410  if (ri == 0)
2411  {
2412  pg_log_error("division by zero");
2413  return false;
2414  }
2415  /* special handling of -1 divisor */
2416  if (ri == -1)
2417  {
2418  if (func == PGBENCH_DIV)
2419  {
2420  /* overflow check (needed for INT64_MIN) */
2421  if (li == PG_INT64_MIN)
2422  {
2423  pg_log_error("bigint div out of range");
2424  return false;
2425  }
2426  else
2427  setIntValue(retval, -li);
2428  }
2429  else
2430  setIntValue(retval, 0);
2431  return true;
2432  }
2433  /* else divisor is not -1 */
2434  if (func == PGBENCH_DIV)
2435  setIntValue(retval, li / ri);
2436  else /* func == PGBENCH_MOD */
2437  setIntValue(retval, li % ri);
2438 
2439  return true;
2440 
2441  default:
2442  /* cannot get here */
2443  Assert(0);
2444  }
2445  }
2446 
2447  Assert(0);
2448  return false; /* NOTREACHED */
2449  }
2450 
2451  /* integer bitwise operators */
2452  case PGBENCH_BITAND:
2453  case PGBENCH_BITOR:
2454  case PGBENCH_BITXOR:
2455  case PGBENCH_LSHIFT:
2456  case PGBENCH_RSHIFT:
2457  {
2458  int64 li,
2459  ri;
2460 
2461  if (!coerceToInt(&vargs[0], &li) || !coerceToInt(&vargs[1], &ri))
2462  return false;
2463 
2464  if (func == PGBENCH_BITAND)
2465  setIntValue(retval, li & ri);
2466  else if (func == PGBENCH_BITOR)
2467  setIntValue(retval, li | ri);
2468  else if (func == PGBENCH_BITXOR)
2469  setIntValue(retval, li ^ ri);
2470  else if (func == PGBENCH_LSHIFT)
2471  setIntValue(retval, li << ri);
2472  else if (func == PGBENCH_RSHIFT)
2473  setIntValue(retval, li >> ri);
2474  else /* cannot get here */
2475  Assert(0);
2476 
2477  return true;
2478  }
2479 
2480  /* logical operators */
2481  case PGBENCH_NOT:
2482  {
2483  bool b;
2484 
2485  if (!coerceToBool(&vargs[0], &b))
2486  return false;
2487 
2488  setBoolValue(retval, !b);
2489  return true;
2490  }
2491 
2492  /* no arguments */
2493  case PGBENCH_PI:
2494  setDoubleValue(retval, M_PI);
2495  return true;
2496 
2497  /* 1 overloaded argument */
2498  case PGBENCH_ABS:
2499  {
2500  PgBenchValue *varg = &vargs[0];
2501 
2502  Assert(nargs == 1);
2503 
2504  if (varg->type == PGBT_INT)
2505  {
2506  int64 i = varg->u.ival;
2507 
2508  setIntValue(retval, i < 0 ? -i : i);
2509  }
2510  else
2511  {
2512  double d = varg->u.dval;
2513 
2514  Assert(varg->type == PGBT_DOUBLE);
2515  setDoubleValue(retval, d < 0.0 ? -d : d);
2516  }
2517 
2518  return true;
2519  }
2520 
2521  case PGBENCH_DEBUG:
2522  {
2523  PgBenchValue *varg = &vargs[0];
2524 
2525  Assert(nargs == 1);
2526 
2527  fprintf(stderr, "debug(script=%d,command=%d): ",
2528  st->use_file, st->command + 1);
2529 
2530  if (varg->type == PGBT_NULL)
2531  fprintf(stderr, "null\n");
2532  else if (varg->type == PGBT_BOOLEAN)
2533  fprintf(stderr, "boolean %s\n", varg->u.bval ? "true" : "false");
2534  else if (varg->type == PGBT_INT)
2535  fprintf(stderr, "int " INT64_FORMAT "\n", varg->u.ival);
2536  else if (varg->type == PGBT_DOUBLE)
2537  fprintf(stderr, "double %.*g\n", DBL_DIG, varg->u.dval);
2538  else /* internal error, unexpected type */
2539  Assert(0);
2540 
2541  *retval = *varg;
2542 
2543  return true;
2544  }
2545 
2546  /* 1 double argument */
2547  case PGBENCH_DOUBLE:
2548  case PGBENCH_SQRT:
2549  case PGBENCH_LN:
2550  case PGBENCH_EXP:
2551  {
2552  double dval;
2553 
2554  Assert(nargs == 1);
2555 
2556  if (!coerceToDouble(&vargs[0], &dval))
2557  return false;
2558 
2559  if (func == PGBENCH_SQRT)
2560  dval = sqrt(dval);
2561  else if (func == PGBENCH_LN)
2562  dval = log(dval);
2563  else if (func == PGBENCH_EXP)
2564  dval = exp(dval);
2565  /* else is cast: do nothing */
2566 
2567  setDoubleValue(retval, dval);
2568  return true;
2569  }
2570 
2571  /* 1 int argument */
2572  case PGBENCH_INT:
2573  {
2574  int64 ival;
2575 
2576  Assert(nargs == 1);
2577 
2578  if (!coerceToInt(&vargs[0], &ival))
2579  return false;
2580 
2581  setIntValue(retval, ival);
2582  return true;
2583  }
2584 
2585  /* variable number of arguments */
2586  case PGBENCH_LEAST:
2587  case PGBENCH_GREATEST:
2588  {
2589  bool havedouble;
2590  int i;
2591 
2592  Assert(nargs >= 1);
2593 
2594  /* need double result if any input is double */
2595  havedouble = false;
2596  for (i = 0; i < nargs; i++)
2597  {
2598  if (vargs[i].type == PGBT_DOUBLE)
2599  {
2600  havedouble = true;
2601  break;
2602  }
2603  }
2604  if (havedouble)
2605  {
2606  double extremum;
2607 
2608  if (!coerceToDouble(&vargs[0], &extremum))
2609  return false;
2610  for (i = 1; i < nargs; i++)
2611  {
2612  double dval;
2613 
2614  if (!coerceToDouble(&vargs[i], &dval))
2615  return false;
2616  if (func == PGBENCH_LEAST)
2617  extremum = Min(extremum, dval);
2618  else
2619  extremum = Max(extremum, dval);
2620  }
2621  setDoubleValue(retval, extremum);
2622  }
2623  else
2624  {
2625  int64 extremum;
2626 
2627  if (!coerceToInt(&vargs[0], &extremum))
2628  return false;
2629  for (i = 1; i < nargs; i++)
2630  {
2631  int64 ival;
2632 
2633  if (!coerceToInt(&vargs[i], &ival))
2634  return false;
2635  if (func == PGBENCH_LEAST)
2636  extremum = Min(extremum, ival);
2637  else
2638  extremum = Max(extremum, ival);
2639  }
2640  setIntValue(retval, extremum);
2641  }
2642  return true;
2643  }
2644 
2645  /* random functions */
2646  case PGBENCH_RANDOM:
2650  {
2651  int64 imin,
2652  imax,
2653  delta;
2654 
2655  Assert(nargs >= 2);
2656 
2657  if (!coerceToInt(&vargs[0], &imin) ||
2658  !coerceToInt(&vargs[1], &imax))
2659  return false;
2660 
2661  /* check random range */
2662  if (unlikely(imin > imax))
2663  {
2664  pg_log_error("empty range given to random");
2665  return false;
2666  }
2667  else if (unlikely(pg_sub_s64_overflow(imax, imin, &delta) ||
2668  pg_add_s64_overflow(delta, 1, &delta)))
2669  {
2670  /* prevent int overflows in random functions */
2671  pg_log_error("random range is too large");
2672  return false;
2673  }
2674 
2675  if (func == PGBENCH_RANDOM)
2676  {
2677  Assert(nargs == 2);
2678  setIntValue(retval, getrand(&st->cs_func_rs, imin, imax));
2679  }
2680  else /* gaussian & exponential */
2681  {
2682  double param;
2683 
2684  Assert(nargs == 3);
2685 
2686  if (!coerceToDouble(&vargs[2], &param))
2687  return false;
2688 
2689  if (func == PGBENCH_RANDOM_GAUSSIAN)
2690  {
2691  if (param < MIN_GAUSSIAN_PARAM)
2692  {
2693  pg_log_error("gaussian parameter must be at least %f (not %f)",
2694  MIN_GAUSSIAN_PARAM, param);
2695  return false;
2696  }
2697 
2698  setIntValue(retval,
2700  imin, imax, param));
2701  }
2702  else if (func == PGBENCH_RANDOM_ZIPFIAN)
2703  {
2704  if (param < MIN_ZIPFIAN_PARAM || param > MAX_ZIPFIAN_PARAM)
2705  {
2706  pg_log_error("zipfian parameter must be in range [%.3f, %.0f] (not %f)",
2708  return false;
2709  }
2710 
2711  setIntValue(retval,
2712  getZipfianRand(&st->cs_func_rs, imin, imax, param));
2713  }
2714  else /* exponential */
2715  {
2716  if (param <= 0.0)
2717  {
2718  pg_log_error("exponential parameter must be greater than zero (not %f)",
2719  param);
2720  return false;
2721  }
2722 
2723  setIntValue(retval,
2725  imin, imax, param));
2726  }
2727  }
2728 
2729  return true;
2730  }
2731 
2732  case PGBENCH_POW:
2733  {
2734  PgBenchValue *lval = &vargs[0];
2735  PgBenchValue *rval = &vargs[1];
2736  double ld,
2737  rd;
2738 
2739  Assert(nargs == 2);
2740 
2741  if (!coerceToDouble(lval, &ld) ||
2742  !coerceToDouble(rval, &rd))
2743  return false;
2744 
2745  setDoubleValue(retval, pow(ld, rd));
2746 
2747  return true;
2748  }
2749 
2750  case PGBENCH_IS:
2751  {
2752  Assert(nargs == 2);
2753 
2754  /*
2755  * note: this simple implementation is more permissive than
2756  * SQL
2757  */
2758  setBoolValue(retval,
2759  vargs[0].type == vargs[1].type &&
2760  vargs[0].u.bval == vargs[1].u.bval);
2761  return true;
2762  }
2763 
2764  /* hashing */
2765  case PGBENCH_HASH_FNV1A:
2766  case PGBENCH_HASH_MURMUR2:
2767  {
2768  int64 val,
2769  seed;
2770 
2771  Assert(nargs == 2);
2772 
2773  if (!coerceToInt(&vargs[0], &val) ||
2774  !coerceToInt(&vargs[1], &seed))
2775  return false;
2776 
2777  if (func == PGBENCH_HASH_MURMUR2)
2778  setIntValue(retval, getHashMurmur2(val, seed));
2779  else if (func == PGBENCH_HASH_FNV1A)
2780  setIntValue(retval, getHashFnv1a(val, seed));
2781  else
2782  /* cannot get here */
2783  Assert(0);
2784 
2785  return true;
2786  }
2787 
2788  case PGBENCH_PERMUTE:
2789  {
2790  int64 val,
2791  size,
2792  seed;
2793 
2794  Assert(nargs == 3);
2795 
2796  if (!coerceToInt(&vargs[0], &val) ||
2797  !coerceToInt(&vargs[1], &size) ||
2798  !coerceToInt(&vargs[2], &seed))
2799  return false;
2800 
2801  if (size <= 0)
2802  {
2803  pg_log_error("permute size parameter must be greater than zero");
2804  return false;
2805  }
2806 
2807  setIntValue(retval, permute(val, size, seed));
2808  return true;
2809  }
2810 
2811  default:
2812  /* cannot get here */
2813  Assert(0);
2814  /* dead code to avoid a compiler warning */
2815  return false;
2816  }
#define Min(x, y)
Definition: c.h:1004
#define Max(x, y)
Definition: c.h:998
#define PG_INT64_MIN
Definition: c.h:591
#define unlikely(x)
Definition: c.h:311
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:219
static bool pg_sub_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:188
static bool pg_add_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:161
static int64 getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
Definition: pgbench.c:1230
static void setIntValue(PgBenchValue *pv, int64 ival)
Definition: pgbench.c:2109
static bool coerceToInt(PgBenchValue *pval, int64 *ival)
Definition: pgbench.c:2044
static int64 getExponentialRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:1112
static void setDoubleValue(PgBenchValue *pv, double dval)
Definition: pgbench.c:2117
#define MIN_ZIPFIAN_PARAM
Definition: pgbench.c:170
static int64 permute(const int64 val, const int64 isize, const int64 seed)
Definition: pgbench.c:1302
#define MAX_FARGS
Definition: pgbench.c:2241
static int64 getHashMurmur2(int64 val, uint64 seed)
Definition: pgbench.c:1269
static int64 getGaussianRand(pg_prng_state *state, int64 min, int64 max, double parameter)
Definition: pgbench.c:1136
#define MIN_GAUSSIAN_PARAM
Definition: pgbench.c:168
#define M_PI
Definition: pgbench.c:73
static int64 getHashFnv1a(int64 val, uint64 seed)
Definition: pgbench.c:1244
static bool coerceToDouble(PgBenchValue *pval, double *dval)
Definition: pgbench.c:2072
#define MAX_ZIPFIAN_PARAM
Definition: pgbench.c:171
@ PGBENCH_DIV
Definition: pgbench.h:70
@ PGBENCH_DOUBLE
Definition: pgbench.h:77
@ PGBENCH_LT
Definition: pgbench.h:98
@ PGBENCH_LN
Definition: pgbench.h:80
@ PGBENCH_RANDOM_EXPONENTIAL
Definition: pgbench.h:84
@ PGBENCH_RSHIFT
Definition: pgbench.h:94
@ PGBENCH_DEBUG
Definition: pgbench.h:72
@ PGBENCH_MOD
Definition: pgbench.h:71
@ PGBENCH_GREATEST
Definition: pgbench.h:75
@ PGBENCH_BITXOR
Definition: pgbench.h:92
@ PGBENCH_RANDOM_ZIPFIAN
Definition: pgbench.h:85
@ PGBENCH_INT
Definition: pgbench.h:76
@ PGBENCH_NE
Definition: pgbench.h:96
@ PGBENCH_LE
Definition: pgbench.h:97
@ PGBENCH_EXP
Definition: pgbench.h:81
@ PGBENCH_PI
Definition: pgbench.h:78
@ PGBENCH_ADD
Definition: pgbench.h:67
@ PGBENCH_EQ
Definition: pgbench.h:95
@ PGBENCH_LSHIFT
Definition: pgbench.h:93
@ PGBENCH_RANDOM
Definition: pgbench.h:82
@ PGBENCH_POW
Definition: pgbench.h:86
@ PGBENCH_IS
Definition: pgbench.h:99
@ PGBENCH_SUB
Definition: pgbench.h:68
@ PGBENCH_HASH_MURMUR2
Definition: pgbench.h:102
@ PGBENCH_ABS
Definition: pgbench.h:73
@ PGBENCH_BITOR
Definition: pgbench.h:91
@ PGBENCH_SQRT
Definition: pgbench.h:79
@ PGBENCH_LEAST
Definition: pgbench.h:74
@ PGBENCH_PERMUTE
Definition: pgbench.h:103
@ PGBENCH_HASH_FNV1A
Definition: pgbench.h:101
@ PGBENCH_NOT
Definition: pgbench.h:89
@ PGBENCH_BITAND
Definition: pgbench.h:90
@ PGBENCH_RANDOM_GAUSSIAN
Definition: pgbench.h:83
@ PGBENCH_MUL
Definition: pgbench.h:69
static pg_noinline void Size size
Definition: slab.c:607
const char * type

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

Referenced by evalFunc().

◆ evaluateExpr()

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

Definition at line 2836 of file pgbench.c.

2838 {
2839  switch (expr->etype)
2840  {
2841  case ENODE_CONSTANT:
2842  {
2843  *retval = expr->u.constant;
2844  return true;
2845  }
2846 
2847  case ENODE_VARIABLE:
2848  {
2849  Variable *var;
2850 
2851  if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2852  {
2853  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2854  return false;
2855  }
2856 
2857  if (!makeVariableValue(var))
2858  return false;
2859 
2860  *retval = var->value;
2861  return true;
2862  }
2863 
2864  case ENODE_FUNCTION:
2865  return evalFunc(st,
2866  expr->u.function.function,
2867  expr->u.function.args,
2868  retval);
2869 
2870  default:
2871  /* internal error which should never occur */
2872  pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2873  }
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1603
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2820
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1663
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:613
PgBenchValue constant
Definition: pgbench.h:115
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
union PgBenchExpr::@37 u
struct PgBenchExpr::@37::@38 variable
PgBenchValue value
Definition: pgbench.c:325

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

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

◆ evaluateSleep()

static bool evaluateSleep ( Variables variables,
int  argc,
char **  argv,
int *  usecs 
)
static

Definition at line 3382 of file pgbench.c.

3384 {
3385  char *var;
3386  int usec;
3387 
3388  if (*argv[1] == ':')
3389  {
3390  if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3391  {
3392  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3393  return false;
3394  }
3395 
3396  usec = atoi(var);
3397 
3398  /* Raise an error if the value of a variable is not a number */
3399  if (usec == 0 && !isdigit((unsigned char) *var))
3400  {
3401  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3402  argv[0], var, argv[1] + 1);
3403  return false;
3404  }
3405  }
3406  else
3407  usec = atoi(argv[1]);
3408 
3409  if (argc > 2)
3410  {
3411  if (pg_strcasecmp(argv[2], "ms") == 0)
3412  usec *= 1000;
3413  else if (pg_strcasecmp(argv[2], "s") == 0)
3414  usec *= 1000000;
3415  }
3416  else
3417  usec *= 1000000;
3418 
3419  *usecs = usec;
3420  return true;
int pg_strcasecmp(const char *s1, const char *s2)
Definition: pgstrcasecmp.c:36

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

Referenced by executeMetaCommand().

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 4284 of file pgbench.c.

4286 {
4287  Command *command = sql_script[st->use_file].commands[st->command];
4288  int argc;
4289  char **argv;
4290 
4291  Assert(command != NULL && command->type == META_COMMAND);
4292 
4293  argc = command->argc;
4294  argv = command->argv;
4295 
4297  {
4299 
4300  initPQExpBuffer(&buf);
4301 
4302  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4303  for (int i = 1; i < argc; i++)
4304  appendPQExpBuffer(&buf, " %s", argv[i]);
4305 
4306  pg_log_debug("%s", buf.data);
4307 
4308  termPQExpBuffer(&buf);
4309  }
4310 
4311  if (command->meta == META_SLEEP)
4312  {
4313  int usec;
4314 
4315  /*
4316  * A \sleep doesn't execute anything, we just get the delay from the
4317  * argument, and enter the CSTATE_SLEEP state. (The per-command
4318  * latency will be recorded in CSTATE_SLEEP state, not here, after the
4319  * delay has elapsed.)
4320  */
4321  if (!evaluateSleep(&st->variables, argc, argv, &usec))
4322  {
4323  commandFailed(st, "sleep", "execution of meta-command failed");
4324  return CSTATE_ABORTED;
4325  }
4326 
4328  st->sleep_until = (*now) + usec;
4329  return CSTATE_SLEEP;
4330  }
4331  else if (command->meta == META_SET)
4332  {
4333  PgBenchExpr *expr = command->expr;
4334  PgBenchValue result;
4335 
4336  if (!evaluateExpr(st, expr, &result))
4337  {
4338  commandFailed(st, argv[0], "evaluation of meta-command failed");
4339  return CSTATE_ABORTED;
4340  }
4341 
4342  if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4343  {
4344  commandFailed(st, "set", "assignment of meta-command failed");
4345  return CSTATE_ABORTED;
4346  }
4347  }
4348  else if (command->meta == META_IF)
4349  {
4350  /* backslash commands with an expression to evaluate */
4351  PgBenchExpr *expr = command->expr;
4352  PgBenchValue result;
4353  bool cond;
4354 
4355  if (!evaluateExpr(st, expr, &result))
4356  {
4357  commandFailed(st, argv[0], "evaluation of meta-command failed");
4358  return CSTATE_ABORTED;
4359  }
4360 
4361  cond = valueTruth(&result);
4363  }
4364  else if (command->meta == META_ELIF)
4365  {
4366  /* backslash commands with an expression to evaluate */
4367  PgBenchExpr *expr = command->expr;
4368  PgBenchValue result;
4369  bool cond;
4370 
4372  {
4373  /* elif after executed block, skip eval and wait for endif. */
4375  return CSTATE_END_COMMAND;
4376  }
4377 
4378  if (!evaluateExpr(st, expr, &result))
4379  {
4380  commandFailed(st, argv[0], "evaluation of meta-command failed");
4381  return CSTATE_ABORTED;
4382  }
4383 
4384  cond = valueTruth(&result);
4387  }
4388  else if (command->meta == META_ELSE)
4389  {
4390  switch (conditional_stack_peek(st->cstack))
4391  {
4392  case IFSTATE_TRUE:
4394  break;
4395  case IFSTATE_FALSE: /* inconsistent if active */
4396  case IFSTATE_IGNORED: /* inconsistent if active */
4397  case IFSTATE_NONE: /* else without if */
4398  case IFSTATE_ELSE_TRUE: /* else after else */
4399  case IFSTATE_ELSE_FALSE: /* else after else */
4400  default:
4401  /* dead code if conditional check is ok */
4402  Assert(false);
4403  }
4404  }
4405  else if (command->meta == META_ENDIF)
4406  {
4409  }
4410  else if (command->meta == META_SETSHELL)
4411  {
4412  if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4413  {
4414  commandFailed(st, "setshell", "execution of meta-command failed");
4415  return CSTATE_ABORTED;
4416  }
4417  }
4418  else if (command->meta == META_SHELL)
4419  {
4420  if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4421  {
4422  commandFailed(st, "shell", "execution of meta-command failed");
4423  return CSTATE_ABORTED;
4424  }
4425  }
4426  else if (command->meta == META_STARTPIPELINE)
4427  {
4428  /*
4429  * In pipeline mode, we use a workflow based on libpq pipeline
4430  * functions.
4431  */
4432  if (querymode == QUERY_SIMPLE)
4433  {
4434  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4435  return CSTATE_ABORTED;
4436  }
4437 
4438  /*
4439  * If we're in prepared-query mode, we need to prepare all the
4440  * commands that are inside the pipeline before we actually start the
4441  * pipeline itself. This solves the problem that running BEGIN
4442  * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4443  * snapshot having been acquired by the prepare within the pipeline.
4444  */
4445  if (querymode == QUERY_PREPARED)
4447 
4448  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4449  {
4450  commandFailed(st, "startpipeline", "already in pipeline mode");
4451  return CSTATE_ABORTED;
4452  }
4453  if (PQenterPipelineMode(st->con) == 0)
4454  {
4455  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4456  return CSTATE_ABORTED;
4457  }
4458  }
4459  else if (command->meta == META_SYNCPIPELINE)
4460  {
4461  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4462  {
4463  commandFailed(st, "syncpipeline", "not in pipeline mode");
4464  return CSTATE_ABORTED;
4465  }
4466  if (PQsendPipelineSync(st->con) == 0)
4467  {
4468  commandFailed(st, "syncpipeline", "failed to send a pipeline sync");
4469  return CSTATE_ABORTED;
4470  }
4471  st->num_syncs++;
4472  }
4473  else if (command->meta == META_ENDPIPELINE)
4474  {
4475  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4476  {
4477  commandFailed(st, "endpipeline", "not in pipeline mode");
4478  return CSTATE_ABORTED;
4479  }
4480  if (!PQpipelineSync(st->con))
4481  {
4482  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4483  return CSTATE_ABORTED;
4484  }
4485  st->num_syncs++;
4486  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4487  /* collect pending results before getting out of pipeline mode */
4488  return CSTATE_WAIT_RESULT;
4489  }
4490 
4491  /*
4492  * executing the expression or shell command might have taken a
4493  * non-negligible amount of time, so reset 'now'
4494  */
4495  *now = 0;
4496 
4497  return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3042
int PQsendPipelineSync(PGconn *conn)
Definition: fe-exec.c:3282
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:712
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3121
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2921
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3382
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1851
pg_time_usec_t sleep_until
Definition: pgbench.c:617
int num_syncs
Definition: pgbench.c:610

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, 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, META_SYNCPIPELINE, now(), CState::num_syncs, PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), PQsendPipelineSync(), prepareCommandsInPipeline(), printfPQExpBuffer(), putVariableValue(), QUERY_PREPARED, QUERY_SIMPLE, querymode, runShellCommand(), CState::sleep_until, sql_script, termPQExpBuffer(), Command::type, unlikely, CState::use_file, valueTruth(), and CState::variables.

Referenced by advanceConnectionState().

◆ executeStatement()

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

Definition at line 1499 of file pgbench.c.

1501 {
1502  PGresult *res;
1503 
1504  res = PQexec(con, sql);
1506  {
1507  pg_log_error("query failed: %s", PQerrorMessage(con));
1508  pg_log_error_detail("Query was: %s", sql);
1509  exit(1);
1510  }
1511  PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2262

References exit(), pg_log_error, pg_log_error_detail, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and res.

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

◆ findBuiltin()

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

Definition at line 6119 of file pgbench.c.

6121 {
6122  int i,
6123  found = 0,
6124  len = strlen(name);
6125  const BuiltinScript *result = NULL;
6126 
6127  for (i = 0; i < lengthof(builtin_script); i++)
6128  {
6129  if (strncmp(builtin_script[i].name, name, len) == 0)
6130  {
6131  result = &builtin_script[i];
6132  found++;
6133  }
6134  }
6135 
6136  /* ok, unambiguous result */
6137  if (found == 1)
6138  return result;
6139 
6140  /* error cases */
6141  if (found == 0)
6142  pg_log_error("no builtin script found for name \"%s\"", name);
6143  else /* found > 1 */
6144  pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6145 
6147  exit(1);
#define lengthof(array)
Definition: c.h:788
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6107
static const BuiltinScript builtin_script[]
Definition: pgbench.c:779

References builtin_script, exit(), i, len, lengthof, listAvailableScripts(), name, and pg_log_error.

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7694 of file pgbench.c.

7696 {
7697  if (st->con != NULL)
7698  {
7699  PQfinish(st->con);
7700  st->con = NULL;
7701  }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5577 of file pgbench.c.

5579 {
5580  termPQExpBuffer(&command->lines);
5581  pg_free(command->first_line);
5582  for (int i = 0; i < command->argc; i++)
5583  pg_free(command->argv[i]);
5584  pg_free(command->varprefix);
5585 
5586  /*
5587  * It should also free expr recursively, but this is currently not needed
5588  * as only gset commands (which do not have an expression) are freed.
5589  */
5590  pg_free(command);

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

Referenced by ParseScript().

◆ free_socket_set()

static void free_socket_set ( socket_set sa)
static

Definition at line 7865 of file pgbench.c.

7867 {
7868  pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ getExponentialRand()

static int64 getExponentialRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 1112 of file pgbench.c.

1115 {
1116  double cut,
1117  uniform,
1118  rand;
1119 
1120  /* abort if wrong parameter, but must really be checked beforehand */
1121  Assert(parameter > 0.0);
1122  cut = exp(-parameter);
1123  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1124  uniform = 1.0 - pg_prng_double(state);
1125 
1126  /*
1127  * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1128  */
1129  Assert((1.0 - cut) != 0.0);
1130  rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1131  /* return int64 random number within between min and max */
1132  return min + (int64) ((max - min + 1) * rand);

References Assert, and pg_prng_double().

Referenced by evalStandardFunc().

◆ getFailures()

static int64 getFailures ( const StatsData stats)
static

Definition at line 4503 of file pgbench.c.

4505 {
4506  return (stats->serialization_failures +
4507  stats->deadlock_failures);

References StatsData::deadlock_failures, and StatsData::serialization_failures.

Referenced by printProgressReport(), and printResults().

◆ getGaussianRand()

static int64 getGaussianRand ( pg_prng_state state,
int64  min,
int64  max,
double  parameter 
)
static

Definition at line 1136 of file pgbench.c.

1139 {
1140  double stdev;
1141  double rand;
1142 
1143  /* abort if parameter is too low, but must really be checked beforehand */
1144  Assert(parameter >= MIN_GAUSSIAN_PARAM);
1145 
1146  /*
1147  * Get normally-distributed random number in the range -parameter <= stdev
1148  * < parameter.
1149  *
1150  * This loop is executed until the number is in the expected range.
1151  *
1152  * As the minimum parameter is 2.0, the probability of looping is low:
1153  * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1154  * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1155  * the worst case. For a parameter value of 5.0, the looping probability
1156  * is about e^{-5} * 2 / pi ~ 0.43%.
1157  */
1158  do
1159  {
1160  stdev = pg_prng_double_normal(state);
1161  }
1162  while (stdev < -parameter || stdev >= parameter);
1163 
1164  /* stdev is in [-parameter, parameter), normalization to [0,1) */
1165  rand = (stdev + parameter) / (parameter * 2.0);
1166 
1167  /* return int64 random number within between min and max */
1168  return min + (int64) ((max - min + 1) * rand);
double pg_prng_double_normal(pg_prng_state *state)
Definition: pg_prng.c:290

References Assert, MIN_GAUSSIAN_PARAM, and pg_prng_double_normal().

Referenced by evalStandardFunc().

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1244 of file pgbench.c.

1246 {
1247  int64 result;
1248  int i;
1249 
1250  result = FNV_OFFSET_BASIS ^ seed;
1251  for (i = 0; i < 8; ++i)
1252  {
1253  int32 octet = val & 0xff;
1254 
1255  val = val >> 8;
1256  result = result ^ octet;
1257  result = result * FNV_PRIME;
1258  }
1259 
1260  return result;
signed int int32
Definition: c.h:494
#define FNV_OFFSET_BASIS
Definition: pgbench.c:84
#define FNV_PRIME
Definition: pgbench.c:83

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1269 of file pgbench.c.

1271 {
1272  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1273  uint64 k = (uint64) val;
1274 
1275  k *= MM2_MUL;
1276  k ^= k >> MM2_ROT;
1277  k *= MM2_MUL;
1278 
1279  result ^= k;
1280  result *= MM2_MUL;
1281 
1282  result ^= result >> MM2_ROT;
1283  result *= MM2_MUL;
1284  result ^= result >> MM2_ROT;
1285 
1286  return (int64) result;
#define MM2_MUL_TIMES_8
Definition: pgbench.c:86
#define MM2_ROT
Definition: pgbench.c:87
#define MM2_MUL
Definition: pgbench.c:85

References MM2_MUL, MM2_MUL_TIMES_8, MM2_ROT, and val.

Referenced by evalStandardFunc().

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2879 of file pgbench.c.

2881 {
2882  MetaCommand mc;
2883 
2884  if (cmd == NULL)
2885  mc = META_NONE;
2886  else if (pg_strcasecmp(cmd, "set") == 0)
2887  mc = META_SET;
2888  else if (pg_strcasecmp(cmd, "setshell") == 0)
2889  mc = META_SETSHELL;
2890  else if (pg_strcasecmp(cmd, "shell") == 0)
2891  mc = META_SHELL;
2892  else if (pg_strcasecmp(cmd, "sleep") == 0)
2893  mc = META_SLEEP;
2894  else if (pg_strcasecmp(cmd, "if") == 0)
2895  mc = META_IF;
2896  else if (pg_strcasecmp(cmd, "elif") == 0)
2897  mc = META_ELIF;
2898  else if (pg_strcasecmp(cmd, "else") == 0)
2899  mc = META_ELSE;
2900  else if (pg_strcasecmp(cmd, "endif") == 0)
2901  mc = META_ENDIF;
2902  else if (pg_strcasecmp(cmd, "gset") == 0)
2903  mc = META_GSET;
2904  else if (pg_strcasecmp(cmd, "aset") == 0)
2905  mc = META_ASET;
2906  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2907  mc = META_STARTPIPELINE;
2908  else if (pg_strcasecmp(cmd, "syncpipeline") == 0)
2909  mc = META_SYNCPIPELINE;
2910  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2911  mc = META_ENDPIPELINE;
2912  else
2913  mc = META_NONE;
2914  return mc;
MetaCommand
Definition: pgbench.c:687

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, META_SYNCPIPELINE, and pg_strcasecmp().

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1178 of file pgbench.c.

1180 {
1181  /*
1182  * Use inverse transform sampling to generate a value > 0, such that the
1183  * expected (i.e. average) value is the given argument.
1184  */
1185  double uniform;
1186 
1187  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1188  uniform = 1.0 - pg_prng_double(state);
1189 
1190  return (int64) (-log(uniform) * center + 0.5);

References pg_prng_double().

Referenced by advanceConnectionState().

◆ getQueryParams()

static void getQueryParams ( Variables variables,
const Command command,
const char **  params 
)
static

Definition at line 1971 of file pgbench.c.

1974 {
1975  int i;
1976 
1977  for (i = 0; i < command->argc - 1; i++)
1978  params[i] = getVariable(variables, command->argv[i + 1]);

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

Referenced by sendCommand().

◆ getrand()

static int64 getrand ( pg_prng_state state,
int64  min,
int64  max 
)
static

Definition at line 1101 of file pgbench.c.

1103 {
1104  return min + (int64) pg_prng_uint64_range(state, 0, max - min);
uint64 pg_prng_uint64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
Definition: pg_prng.c:144

References pg_prng_uint64_range().

Referenced by chooseScript(), and evalStandardFunc().

◆ getResultString()

static const char* getResultString ( bool  skipped,
EStatus  estatus 
)
static

Definition at line 4514 of file pgbench.c.

4516 {
4517  if (skipped)
4518  return "skipped";
4519  else if (failures_detailed)
4520  {
4521  switch (estatus)
4522  {
4524  return "serialization";
4526  return "deadlock";
4527  default:
4528  /* internal error which should never occur */
4529  pg_fatal("unexpected error status: %d", estatus);
4530  }
4531  }
4532  else
4533  return "failed";

References ESTATUS_DEADLOCK_ERROR, ESTATUS_SERIALIZATION_ERROR, failures_detailed, and pg_fatal.

Referenced by doLog().

◆ getSQLErrorStatus()

static EStatus getSQLErrorStatus ( const char *  sqlState)
static

Definition at line 3207 of file pgbench.c.

3209 {
3210  if (sqlState != NULL)
3211  {
3212  if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3214  else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3215  return ESTATUS_DEADLOCK_ERROR;
3216  }
3217 
3218  return ESTATUS_OTHER_SQL_ERROR;
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:77
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76

References ERRCODE_T_R_DEADLOCK_DETECTED, ERRCODE_T_R_SERIALIZATION_FAILURE, ESTATUS_DEADLOCK_ERROR, ESTATUS_OTHER_SQL_ERROR, and ESTATUS_SERIALIZATION_ERROR.

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5307 of file pgbench.c.

5309 {
5310  PGresult *res;
5311 
5312  /*
5313  * get the scaling factor that should be same as count(*) from
5314  * pgbench_branches if this is not a custom query
5315  */
5316  res = PQexec(con, "select count(*) from pgbench_branches");
5318  {
5319  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5320 
5321  pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5322 
5323  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5324  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5325  PQdb(con));
5326 
5327  exit(1);
5328  }
5329  scale = atoi(PQgetvalue(res, 0, 0));
5330  if (scale < 0)
5331  pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5332  PQgetvalue(res, 0, 0));
5333  PQclear(res);
5334 
5335  /* warn if we override user-given -s switch */
5336  if (scale_given)
5337  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5338  scale);
5339 
5340  /*
5341  * Get the partition information for the first "pgbench_accounts" table
5342  * found in search_path.
5343  *
5344  * The result is empty if no "pgbench_accounts" is found.
5345  *
5346  * Otherwise, it always returns one row even if the table is not
5347  * partitioned (in which case the partition strategy is NULL).
5348  *
5349  * The number of partitions can be 0 even for partitioned tables, if no
5350  * partition is attached.
5351  *
5352  * We assume no partitioning on any failure, so as to avoid failing on an
5353  * old version without "pg_partitioned_table".
5354  */
5355  res = PQexec(con,
5356  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5357  "from pg_catalog.pg_class as c "
5358  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5359  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5360  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5361  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5362  "where c.relname = 'pgbench_accounts' and o.n is not null "
5363  "group by 1, 2 "
5364  "order by 1 asc "
5365  "limit 1");
5366 
5368  {
5369  /* probably an older version, coldly assume no partitioning */
5371  partitions = 0;
5372  }
5373  else if (PQntuples(res) == 0)
5374  {
5375  /*
5376  * This case is unlikely as pgbench already found "pgbench_branches"
5377  * above to compute the scale.
5378  */
5379  pg_log_error("no pgbench_accounts table found in search_path");
5380  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5381  exit(1);
5382  }
5383  else /* PQntuples(res) == 1 */
5384  {
5385  /* normal case, extract partition information */
5386  if (PQgetisnull(res, 0, 1))
5388  else
5389  {
5390  char *ps = PQgetvalue(res, 0, 1);
5391 
5392  /* column must be there */
5393  Assert(ps != NULL);
5394 
5395  if (strcmp(ps, "r") == 0)
5397  else if (strcmp(ps, "h") == 0)
5399  else
5400  {
5401  /* possibly a newer version with new partition method */
5402  pg_fatal("unexpected partition method: \"%s\"", ps);
5403  }
5404  }
5405 
5406  partitions = atoi(PQgetvalue(res, 0, 2));
5407  }
5408 
5409  PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6993
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3481
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3876
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3901
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3466
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:103
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:56

References Assert, ERRCODE_UNDEFINED_TABLE, exit(), PART_HASH, PART_NONE, PART_RANGE, partition_method, partitions, PG_DIAG_SQLSTATE, pg_fatal, pg_log_error, pg_log_error_hint, pg_log_warning, PGRES_TUPLES_OK, PQclear(), PQdb(), PQerrorMessage(), PQexec(), PQgetisnull(), PQgetvalue(), PQntuples(), PQresultErrorField(), PQresultStatus(), ps, res, and scale.

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3513 of file pgbench.c.

3515 {
3516  PGTransactionStatusType tx_status;
3517 
3518  tx_status = PQtransactionStatus(con);
3519  switch (tx_status)
3520  {
3521  case PQTRANS_IDLE:
3522  return TSTATUS_IDLE;
3523  case PQTRANS_INTRANS:
3524  case PQTRANS_INERROR:
3525  return TSTATUS_IN_BLOCK;
3526  case PQTRANS_UNKNOWN:
3527  /* PQTRANS_UNKNOWN is expected given a broken connection */
3528  if (PQstatus(con) == CONNECTION_BAD)
3529  return TSTATUS_CONN_ERROR;
3530  /* fall through */
3531  case PQTRANS_ACTIVE:
3532  default:
3533 
3534  /*
3535  * We cannot find out whether we are in a transaction block or
3536  * not. Internal error which should never occur.
3537  */
3538  pg_log_error("unexpected transaction status %d", tx_status);
3539  return TSTATUS_OTHER_ERROR;
3540  }
3541 
3542  /* not reached */
3543  Assert(false);
3544  return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7102
PGTransactionStatusType
Definition: libpq-fe.h:121
@ PQTRANS_INTRANS
Definition: libpq-fe.h:124
@ PQTRANS_IDLE
Definition: libpq-fe.h:122
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:123
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:126
@ PQTRANS_INERROR
Definition: libpq-fe.h:125

References Assert, CONNECTION_BAD, pg_log_error, PQstatus(), PQTRANS_ACTIVE, PQTRANS_IDLE, PQTRANS_INERROR, PQTRANS_INTRANS, PQTRANS_UNKNOWN, PQtransactionStatus(), TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, and TSTATUS_OTHER_ERROR.

Referenced by advanceConnectionState().

◆ getVariable()

static char* getVariable ( Variables variables,
char *  name 
)
static

Definition at line 1630 of file pgbench.c.

1632 {
1633  Variable *var;
1634  char stringform[64];
1635 
1636  var = lookupVariable(variables, name);
1637  if (var == NULL)
1638  return NULL; /* not found */
1639 
1640  if (var->svalue)
1641  return var->svalue; /* we have it in string form */
1642 
1643  /* We need to produce a string equivalent of the value */
1644  Assert(var->value.type != PGBT_NO_VALUE);
1645  if (var->value.type == PGBT_NULL)
1646  snprintf(stringform, sizeof(stringform), "NULL");
1647  else if (var->value.type == PGBT_BOOLEAN)
1648  snprintf(stringform, sizeof(stringform),
1649  "%s", var->value.u.bval ? "true" : "false");
1650  else if (var->value.type == PGBT_INT)
1651  snprintf(stringform, sizeof(stringform),
1652  INT64_FORMAT, var->value.u.ival);
1653  else if (var->value.type == PGBT_DOUBLE)
1654  snprintf(stringform, sizeof(stringform),
1655  "%.*g", DBL_DIG, var->value.u.dval);
1656  else /* internal error, unexpected type */
1657  Assert(0);
1658  var->svalue = pg_strdup(stringform);
1659  return var->svalue;
char * pg_strdup(const char *in)
Definition: fe_memutils.c:85
@ PGBT_NO_VALUE
Definition: pgbench.h:36
#define snprintf
Definition: port.h:238
char * svalue
Definition: pgbench.c:324

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

◆ getZipfianRand()

static int64 getZipfianRand ( pg_prng_state state,
int64  min,
int64  max,
double  s 
)
static

Definition at line 1230 of file pgbench.c.

1232 {
1233  int64 n = max - min + 1;
1234 
1235  /* abort if parameter is invalid */
1237 
1238  return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1200

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

Referenced by evalStandardFunc().

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 7710 of file pgbench.c.

7712 {
7713  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4930 of file pgbench.c.

4932 {
4933  /* "filler" column defaults to blank padded empty string */
4934  printfPQExpBuffer(sql,
4935  INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4936  curr + 1, curr / naccounts + 1);

References INT64_FORMAT, naccounts, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initBranch()

static void initBranch ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4912 of file pgbench.c.

4914 {
4915  /* "filler" column uses NULL */
4916  printfPQExpBuffer(sql,
4917  INT64_FORMAT "\t0\t\\N\n",
4918  curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5176 of file pgbench.c.

5178 {
5179  static const char *const DDLKEYs[] = {
5180  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5181  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5182  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5183  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5184  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5185  };
5186  int i;
5187 
5188  fprintf(stderr, "creating foreign keys...\n");
5189  for (i = 0; i < lengthof(DDLKEYs); i++)
5190  {
5191  executeStatement(con, DDLKEYs[i]);
5192  }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5138 of file pgbench.c.

5140 {
5141  static const char *const DDLINDEXes[] = {
5142  "alter table pgbench_branches add primary key (bid)",
5143  "alter table pgbench_tellers add primary key (tid)",
5144  "alter table pgbench_accounts add primary key (aid)"
5145  };
5146  int i;
5147  PQExpBufferData query;
5148 
5149  fprintf(stderr, "creating primary keys...\n");
5150  initPQExpBuffer(&query);
5151 
5152  for (i = 0; i < lengthof(DDLINDEXes); i++)
5153  {
5154  resetPQExpBuffer(&query);
5155  appendPQExpBufferStr(&query, DDLINDEXes[i]);
5156 
5157  if (index_tablespace != NULL)
5158  {
5159  char *escape_tablespace;
5160 
5161  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5162  strlen(index_tablespace));
5163  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5164  PQfreemem(escape_tablespace);
5165  }
5166 
5167  executeStatement(con, query.data);
5168  }
5169 
5170  termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4032
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4310
char * index_tablespace
Definition: pgbench.c:217
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146

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

Referenced by runInitSteps().

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4807 of file pgbench.c.

4809 {
4810  /*
4811  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4812  * fields in these table declarations were intended to comply with that.
4813  * The pgbench_accounts table complies with that because the "filler"
4814  * column is set to blank-padded empty string. But for all other tables
4815  * the columns default to NULL and so don't actually take any space. We
4816  * could fix that by giving them non-null default values. However, that
4817  * would completely break comparability of pgbench results with prior
4818  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4819  * anyway, we stick with the historical behavior.
4820  */
4821  struct ddlinfo
4822  {
4823  const char *table; /* table name */
4824  const char *smcols; /* column decls if accountIDs are 32 bits */
4825  const char *bigcols; /* column decls if accountIDs are 64 bits */
4826  int declare_fillfactor;
4827  };
4828  static const struct ddlinfo DDLs[] = {
4829  {
4830  "pgbench_history",
4831  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4832  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4833  0
4834  },
4835  {
4836  "pgbench_tellers",
4837  "tid int not null,bid int,tbalance int,filler char(84)",
4838  "tid int not null,bid int,tbalance int,filler char(84)",
4839  1
4840  },
4841  {
4842  "pgbench_accounts",
4843  "aid int not null,bid int,abalance int,filler char(84)",
4844  "aid bigint not null,bid int,abalance int,filler char(84)",
4845  1
4846  },
4847  {
4848  "pgbench_branches",
4849  "bid int not null,bbalance int,filler char(88)",
4850  "bid int not null,bbalance int,filler char(88)",
4851  1
4852  }
4853  };
4854  int i;
4855  PQExpBufferData query;
4856 
4857  fprintf(stderr, "creating tables...\n");
4858 
4859  initPQExpBuffer(&query);
4860 
4861  for (i = 0; i < lengthof(DDLs); i++)
4862  {
4863  const struct ddlinfo *ddl = &DDLs[i];
4864 
4865  /* Construct new create table statement. */
4866  printfPQExpBuffer(&query, "create%s table %s(%s)",
4867  unlogged_tables ? " unlogged" : "",
4868  ddl->table,
4869  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4870 
4871  /* Partition pgbench_accounts table */
4872  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4873  appendPQExpBuffer(&query,
4874  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4875  else if (ddl->declare_fillfactor)
4876  {
4877  /* fillfactor is only expected on actual tables */
4878  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4879  }
4880 
4881  if (tablespace != NULL)
4882  {
4883  char *escape_tablespace;
4884 
4885  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4886  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4887  PQfreemem(escape_tablespace);
4888  }
4889 
4890  executeStatement(con, query.data);
4891  }
4892 
4893  termPQExpBuffer(&query);
4894 
4895  if (partition_method != PART_NONE)
4896  createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4738
static const char *const PARTITION_METHOD[]
Definition: pgbench.c:234
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:254
char * tablespace
Definition: pgbench.c:216

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

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4716 of file pgbench.c.

4718 {
4719  fprintf(stderr, "dropping old tables...\n");
4720 
4721  /*
4722  * We drop all the tables in one command, so that whether there are
4723  * foreign key dependencies or not doesn't matter.
4724  */
4725  executeStatement(con, "drop table if exists "
4726  "pgbench_accounts, "
4727  "pgbench_branches, "
4728  "pgbench_history, "
4729  "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5048 of file pgbench.c.

5050 {
5051  fprintf(stderr, "generating data (client-side)...\n");
5052 
5053  /*
5054  * we do all of this in one transaction to enable the backend's
5055  * data-loading optimizations
5056  */
5057  executeStatement(con, "begin");
5058 
5059  /* truncate away any old data */
5060  initTruncateTables(con);
5061 
5062  /*
5063  * fill branches, tellers, accounts in that order in case foreign keys
5064  * already exist
5065  */
5066  initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5067  initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5068  initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5069 
5070  executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4921
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4912
#define ntellers
Definition: pgbench.c:244
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4902
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4930
#define nbranches
Definition: pgbench.c:243
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4939

References executeStatement(), fprintf, initAccount(), initBranch(), initPopulateTable(), initTeller(), initTruncateTables(), naccounts, nbranches, and ntellers.

Referenced by runInitSteps().

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 5080 of file pgbench.c.

5082 {
5083  PQExpBufferData sql;
5084 
5085  fprintf(stderr, "generating data (server-side)...\n");
5086 
5087  /*
5088  * we do all of this in one transaction to enable the backend's
5089  * data-loading optimizations
5090  */
5091  executeStatement(con, "begin");
5092 
5093  /* truncate away any old data */
5094  initTruncateTables(con);
5095 
5096  initPQExpBuffer(&sql);
5097 
5098  printfPQExpBuffer(&sql,
5099  "insert into pgbench_branches(bid,bbalance) "
5100  "select bid, 0 "
5101  "from generate_series(1, %d) as bid", nbranches * scale);
5102  executeStatement(con, sql.data);
5103 
5104  printfPQExpBuffer(&sql,
5105  "insert into pgbench_tellers(tid,bid,tbalance) "
5106  "select tid, (tid - 1) / %d + 1, 0 "
5107  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5108  executeStatement(con, sql.data);
5109 
5110  printfPQExpBuffer(&sql,
5111  "insert into pgbench_accounts(aid,bid,abalance,filler) "
5112  "select aid, (aid - 1) / %d + 1, 0, '' "
5113  "from generate_series(1, " INT64_FORMAT ") as aid",
5114  naccounts, (int64) naccounts * scale);
5115  executeStatement(con, sql.data);
5116 
5117  termPQExpBuffer(&sql);
5118 
5119  executeStatement(con, "commit");

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

Referenced by runInitSteps().

◆ initPopulateTable()

static void initPopulateTable ( PGconn con,
const char *  table,
int64  base,
initRowMethod  init_row 
)
static

Definition at line 4939 of file pgbench.c.

4942 {
4943  int n;
4944  int64 k;
4945  int chars = 0;
4946  PGresult *res;
4947  PQExpBufferData sql;
4948  char copy_statement[256];
4949  const char *copy_statement_fmt = "copy %s from stdin";
4950  int64 total = base * scale;
4951 
4952  /* used to track elapsed time and estimate of the remaining time */
4954  int log_interval = 1;
4955 
4956  /* Stay on the same line if reporting to a terminal */
4957  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4958 
4959  initPQExpBuffer(&sql);
4960 
4961  /*
4962  * Use COPY with FREEZE on v14 and later for all the tables except
4963  * pgbench_accounts when it is partitioned.
4964  */
4965  if (PQserverVersion(con) >= 140000)
4966  {
4967  if (strcmp(table, "pgbench_accounts") != 0 ||
4968  partitions == 0)
4969  copy_statement_fmt = "copy %s from stdin with (freeze on)";
4970  }
4971 
4972  n = pg_snprintf(copy_statement, sizeof(copy_statement), copy_statement_fmt, table);
4973  if (n >= sizeof(copy_statement))
4974  pg_fatal("invalid buffer size: must be at least %d characters long", n);
4975  else if (n == -1)
4976  pg_fatal("invalid format string");
4977 
4978  res = PQexec(con, copy_statement);
4979 
4981  pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4982  PQclear(res);
4983 
4984  start = pg_time_now();
4985 
4986  for (k = 0; k < total; k++)
4987  {
4988  int64 j = k + 1;
4989 
4990  init_row(&sql, k);
4991  if (PQputline(con, sql.data))
4992  pg_fatal("PQputline failed");
4993 
4994  if (CancelRequested)
4995  break;
4996 
4997  /*
4998  * If we want to stick with the original logging, print a message each
4999  * 100k inserted rows.
5000  */
5001  if ((!use_quiet) && (j % 100000 == 0))
5002  {
5003  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5004  double remaining_sec = ((double) total - j) * elapsed_sec / j;
5005 
5006  chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)%c",
5007  j, total,
5008  (int) ((j * 100) / total),
5009  table, elapsed_sec, remaining_sec, eol);
5010  }
5011  /* let's not call the timing for each row, but only each 100 rows */
5012  else if (use_quiet && (j % 100 == 0))
5013  {
5014  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5015  double remaining_sec = ((double) total - j) * elapsed_sec / j;
5016 
5017  /* have we reached the next interval (or end)? */
5018  if ((j == total) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
5019  {
5020  chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)%c",
5021  j, total,
5022  (int) ((j * 100) / total),
5023  table, elapsed_sec, remaining_sec, eol);
5024 
5025  /* skip to the next interval */
5026  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
5027  }
5028  }
5029  }
5030 
5031  if (chars != 0 && eol != '\n')
5032  fprintf(stderr, "%*c\r", chars - 1, ' '); /* Clear the current line */
5033 
5034  if (PQputline(con, "\\.\n"))
5035  pg_fatal("very last PQputline failed");
5036  if (PQendcopy(con))
5037  pg_fatal("PQendcopy failed");
5038 
5039  termPQExpBuffer(&sql);
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7137
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2949
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2918
int j
Definition: isn.c:74
@ PGRES_COPY_IN
Definition: libpq-fe.h:107
#define LOG_STEP_SECONDS
Definition: pgbench.c:165
bool use_quiet
Definition: pgbench.c:257
int int pg_snprintf(char *str, size_t count, const char *fmt,...) pg_attribute_printf(3
static char chars[TZ_MAX_CHARS]
Definition: zic.c:401

References CancelRequested, chars, PQExpBufferData::data, fprintf, initPQExpBuffer(), INT64_FORMAT, j, LOG_STEP_SECONDS, partitions, pg_fatal, pg_snprintf(), PG_TIME_GET_DOUBLE, pg_time_now(), PGRES_COPY_IN, PQclear(), PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus(), PQserverVersion(), res, scale, start, termPQExpBuffer(), and use_quiet.

Referenced by initGenerateDataClientSide().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 1087 of file pgbench.c.

1089 {
uint64 pg_prng_uint64(pg_prng_state *state)
Definition: pg_prng.c:134
void pg_prng_seed(pg_prng_state *state, uint64 seed)
Definition: pg_prng.c:89
static pg_prng_state base_random_sequence
Definition: pgbench.c:476

References base_random_sequence, pg_prng_seed(), and pg_prng_uint64().

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1393 of file pgbench.c.

1395 {
1396  memset(ss, 0, sizeof(SimpleStats));

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

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

◆ initTeller()

static void initTeller ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4921 of file pgbench.c.

4923 {
4924  /* "filler" column uses NULL */
4925  printfPQExpBuffer(sql,
4926  INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n",
4927  curr + 1, curr / ntellers + 1);

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4902 of file pgbench.c.

4904 {
4905  executeStatement(con, "truncate table "
4906  "pgbench_accounts, "
4907  "pgbench_branches, "
4908  "pgbench_history, "
4909  "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5125 of file pgbench.c.

5127 {
5128  fprintf(stderr, "vacuuming...\n");
5129  executeStatement(con, "vacuum analyze pgbench_branches");
5130  executeStatement(con, "vacuum analyze pgbench_tellers");
5131  executeStatement(con, "vacuum analyze pgbench_accounts");
5132  executeStatement(con, "vacuum analyze pgbench_history");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ is_an_int()

static bool is_an_int ( const char *  str)
static

Definition at line 950 of file pgbench.c.

952 {
953  const char *ptr = str;
954 
955  /* skip leading spaces; cast is consistent with strtoint64 */
956  while (*ptr && isspace((unsigned char) *ptr))
957  ptr++;
958 
959  /* skip sign */
960  if (*ptr == '+' || *ptr == '-')
961  ptr++;
962 
963  /* at least one digit */
964  if (*ptr && !isdigit((unsigned char) *ptr))
965  return false;
966 
967  /* eat all digits */
968  while (*ptr && isdigit((unsigned char) *ptr))
969  ptr++;
970 
971  /* must have reached end of string */
972  return *ptr == '\0';
const char * str

References str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 2124 of file pgbench.c.

2126 {
2127  return func == PGBENCH_AND || func == PGBENCH_OR || func == PGBENCH_CASE;

References PGBENCH_AND, PGBENCH_CASE, and PGBENCH_OR.

Referenced by evalFunc(), and evalLazyFunc().

◆ listAvailableScripts()

static void listAvailableScripts ( void  )
static

Definition at line 6107 of file pgbench.c.

6109 {
6110  int i;
6111 
6112  fprintf(stderr, "Available builtin scripts:\n");
6113  for (i = 0; i < lengthof(builtin_script); i++)
6114  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6115  fprintf(stderr, "\n");

References builtin_script, fprintf, i, lengthof, and name.

Referenced by findBuiltin(), and main().

◆ lookupCreateVariable()

static Variable* lookupCreateVariable ( Variables variables,
const char *  context,
char *  name 
)
static

Definition at line 1791 of file pgbench.c.

1793 {
1794  Variable *var;
1795 
1796  var = lookupVariable(variables, name);
1797  if (var == NULL)
1798  {
1799  /*
1800  * Check for the name only when declaring a new variable to avoid
1801  * overhead.
1802  */
1803  if (!valid_variable_name(name))
1804  {
1805  pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1806  return NULL;
1807  }
1808 
1809  /* Create variable at the end of the array */
1810  enlargeVariables(variables, 1);
1811 
1812  var = &(variables->vars[variables->nvars]);
1813 
1814  var->name = pg_strdup(name);
1815  var->svalue = NULL;
1816  /* caller is expected to initialize remaining fields */
1817 
1818  variables->nvars++;
1819  /* we don't re-sort the array till we have to */
1820  variables->vars_sorted = false;
1821  }
1822 
1823  return var;
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1737
static void enlargeVariables(Variables *variables, int needed)
Definition: pgbench.c:1772
tree context
Definition: radixtree.h:1829
char * name
Definition: pgbench.c:323
bool vars_sorted
Definition: pgbench.c:343

References context, enlargeVariables(), lookupVariable(), name, Variable::name, Variables::nvars, pg_log_error, pg_strdup(), Variable::svalue, valid_variable_name(), Variables::vars, and Variables::vars_sorted.

Referenced by putVariable(), and putVariableValue().

◆ lookupVariable()

static Variable* lookupVariable ( Variables variables,
char *  name 
)
static

Definition at line 1603 of file pgbench.c.

1605 {
1606  Variable key;
1607 
1608  /* On some versions of Solaris, bsearch of zero items dumps core */
1609  if (variables->nvars <= 0)
1610  return NULL;
1611 
1612  /* Sort if we have to */
1613  if (!variables->vars_sorted)
1614  {
1615  qsort(variables->vars, variables->nvars, sizeof(Variable),
1617  variables->vars_sorted = true;
1618  }
1619 
1620  /* Now we can search */
1621  key.name = name;
1622  return (Variable *) bsearch(&key,
1623  variables->vars,
1624  variables->nvars,
1625  sizeof(Variable),
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1595
#define qsort(a, b, c, d)
Definition: port.h:449

References compareVariableNames(), sort-test::key, name, Variables::nvars, qsort, Variables::vars, and Variables::vars_sorted.

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

◆ main()

int main ( int  argc,
char **  argv 
)

Definition at line 6616 of file pgbench.c.

6618 {
6619  static struct option long_options[] = {
6620  /* systematic long/short named options */
6621  {"builtin", required_argument, NULL, 'b'},
6622  {"client", required_argument, NULL, 'c'},
6623  {"connect", no_argument, NULL, 'C'},
6624  {"dbname", required_argument, NULL, 'd'},
6625  {"define", required_argument, NULL, 'D'},
6626  {"file", required_argument, NULL, 'f'},
6627  {"fillfactor", required_argument, NULL, 'F'},
6628  {"host", required_argument, NULL, 'h'},
6629  {"initialize", no_argument, NULL, 'i'},
6630  {"init-steps", required_argument, NULL, 'I'},
6631  {"jobs", required_argument, NULL, 'j'},
6632  {"log", no_argument, NULL, 'l'},
6633  {"latency-limit", required_argument, NULL, 'L'},
6634  {"no-vacuum", no_argument, NULL, 'n'},
6635  {"port", required_argument, NULL, 'p'},
6636  {"progress", required_argument, NULL, 'P'},
6637  {"protocol", required_argument, NULL, 'M'},
6638  {"quiet", no_argument, NULL, 'q'},
6639  {"report-per-command", no_argument, NULL, 'r'},
6640  {"rate", required_argument, NULL, 'R'},
6641  {"scale", required_argument, NULL, 's'},
6642  {"select-only", no_argument, NULL, 'S'},
6643  {"skip-some-updates", no_argument, NULL, 'N'},
6644  {"time", required_argument, NULL, 'T'},
6645  {"transactions", required_argument, NULL, 't'},
6646  {"username", required_argument, NULL, 'U'},
6647  {"vacuum-all", no_argument, NULL, 'v'},
6648  /* long-named only options */
6649  {"unlogged-tables", no_argument, NULL, 1},
6650  {"tablespace", required_argument, NULL, 2},
6651  {"index-tablespace", required_argument, NULL, 3},
6652  {"sampling-rate", required_argument, NULL, 4},
6653  {"aggregate-interval", required_argument, NULL, 5},
6654  {"progress-timestamp", no_argument, NULL, 6},
6655  {"log-prefix", required_argument, NULL, 7},
6656  {"foreign-keys", no_argument, NULL, 8},
6657  {"random-seed", required_argument, NULL, 9},
6658  {"show-script", required_argument, NULL, 10},
6659  {"partitions", required_argument, NULL, 11},
6660  {"partition-method", required_argument, NULL, 12},
6661  {"failures-detailed", no_argument, NULL, 13},
6662  {"max-tries", required_argument, NULL, 14},
6663  {"verbose-errors", no_argument, NULL, 15},
6664  {"exit-on-abort", no_argument, NULL, 16},
6665  {"debug", no_argument, NULL, 17},
6666  {NULL, 0, NULL, 0}
6667  };
6668 
6669  int c;
6670  bool is_init_mode = false; /* initialize mode? */
6671  char *initialize_steps = NULL;
6672  bool foreign_keys = false;
6673  bool is_no_vacuum = false;
6674  bool do_vacuum_accounts = false; /* vacuum accounts table? */
6675  int optindex;
6676  bool scale_given = false;
6677 
6678  bool benchmarking_option_set = false;
6679  bool initialization_option_set = false;
6680  bool internal_script_used = false;
6681 
6682  CState *state; /* status of clients */
6683  TState *threads; /* array of thread */
6684 
6686  start_time, /* start up time */
6687  bench_start = 0, /* first recorded benchmarking time */
6688  conn_total_duration; /* cumulated connection time in
6689  * threads */
6690  int64 latency_late = 0;
6691  StatsData stats;
6692  int weight;
6693 
6694  int i;
6695  int nclients_dealt;
6696 
6697 #ifdef HAVE_GETRLIMIT
6698  struct rlimit rlim;
6699 #endif
6700 
6701  PGconn *con;
6702  char *env;
6703 
6704  int exit_code = 0;
6705  struct timeval tv;
6706 
6707  /*
6708  * Record difference between Unix time and instr_time time. We'll use
6709  * this for logging and aggregation.
6710  */
6711  gettimeofday(&tv, NULL);
6712  epoch_shift = tv.tv_sec * INT64CONST(1000000) + tv.tv_usec - pg_time_now();
6713 
6714  pg_logging_init(argv[0]);
6715  progname = get_progname(argv[0]);
6716 
6717  if (argc > 1)
6718  {
6719  if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
6720  {
6721  usage();
6722  exit(0);
6723  }
6724  if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
6725  {
6726  puts("pgbench (PostgreSQL) " PG_VERSION);
6727  exit(0);
6728  }
6729  }
6730 
6731  state = (CState *) pg_malloc0(sizeof(CState));
6732 
6733  /* set random seed early, because it may be used while parsing scripts. */
6734  if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
6735  pg_fatal("error while setting random seed from PGBENCH_RANDOM_SEED environment variable");
6736 
6737  while ((c = getopt_long(argc, argv, "b:c:Cd:D:f:F:h:iI:j:lL:M:nNp:P:qrR:s:St:T:U:v", long_options, &optindex)) != -1)
6738  {
6739  char *script;
6740 
6741  switch (c)
6742  {
6743  case 'b':
6744  if (strcmp(optarg, "list") == 0)
6745  {
6747  exit(0);
6748  }
6749  weight = parseScriptWeight(optarg, &script);
6750  process_builtin(findBuiltin(script), weight);
6751  benchmarking_option_set = true;
6752  internal_script_used = true;
6753  break;
6754  case 'c':
6755  benchmarking_option_set = true;
6756  if (!option_parse_int(optarg, "-c/--clients", 1, INT_MAX,
6757  &nclients))
6758  {
6759  exit(1);
6760  }
6761 #ifdef HAVE_GETRLIMIT
6762  if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
6763  pg_fatal("getrlimit failed: %m");
6764  if (rlim.rlim_cur < nclients + 3)
6765  {
6766  pg_log_error("need at least %d open files, but system limit is %ld",
6767  nclients + 3, (long) rlim.rlim_cur);
6768  pg_log_error_hint("Reduce number of clients, or use limit/ulimit to increase the system limit.");
6769  exit(1);
6770  }
6771 #endif /* HAVE_GETRLIMIT */
6772  break;
6773  case 'C':
6774  benchmarking_option_set = true;
6775  is_connect = true;
6776  break;
6777  case 'd':
6778  dbName = pg_strdup(optarg);
6779  break;
6780  case 'D':
6781  {
6782  char *p;
6783 
6784  benchmarking_option_set = true;
6785 
6786  if ((p = strchr(optarg, '=')) == NULL || p == optarg || *(p + 1) == '\0')
6787  pg_fatal("invalid variable definition: \"%s\"", optarg);
6788 
6789  *p++ = '\0';
6790  if (!putVariable(&state[0].variables, "option", optarg, p))
6791  exit(1);
6792  }
6793  break;
6794  case 'f':
6795  weight = parseScriptWeight(optarg, &script);
6796  process_file(script, weight);
6797  benchmarking_option_set = true;
6798  break;
6799  case 'F':
6800  initialization_option_set = true;
6801  if (!option_parse_int(optarg, "-F/--fillfactor", 10, 100,
6802  &fillfactor))
6803  exit(1);
6804  break;
6805  case 'h':
6806  pghost = pg_strdup(optarg);
6807  break;
6808  case 'i':
6809  is_init_mode = true;
6810  break;
6811  case 'I':
6812  pg_free(initialize_steps);
6813  initialize_steps = pg_strdup(optarg);
6814  checkInitSteps(initialize_steps);
6815  initialization_option_set = true;
6816  break;
6817  case 'j': /* jobs */
6818  benchmarking_option_set = true;
6819  if (!option_parse_int(optarg, "-j/--jobs", 1, INT_MAX,
6820  &nthreads))
6821  {
6822  exit(1);
6823  }
6824  break;
6825  case 'l':
6826  benchmarking_option_set = true;
6827  use_log = true;
6828  break;
6829  case 'L':
6830  {
6831  double limit_ms = atof(optarg);
6832 
6833  if (limit_ms <= 0.0)
6834  pg_fatal("invalid latency limit: \"%s\"", optarg);
6835  benchmarking_option_set = true;
6836  latency_limit = (int64) (limit_ms * 1000);
6837  }
6838  break;
6839  case 'M':
6840  benchmarking_option_set = true;
6841  for (querymode = 0; querymode < NUM_QUERYMODE; querymode++)
6842  if (strcmp(optarg, QUERYMODE[querymode]) == 0)
6843  break;
6844  if (querymode >= NUM_QUERYMODE)
6845  pg_fatal("invalid query mode (-M): \"%s\"", optarg);
6846  break;
6847  case 'n':
6848  is_no_vacuum = true;
6849  break;
6850  case 'N':
6851  process_builtin(findBuiltin("simple-update"), 1);
6852  benchmarking_option_set = true;
6853  internal_script_used = true;
6854  break;
6855  case 'p':
6856  pgport = pg_strdup(optarg);
6857  break;
6858  case 'P':
6859  benchmarking_option_set = true;
6860  if (!option_parse_int(optarg, "-P/--progress", 1, INT_MAX,
6861  &progress))
6862  exit(1);
6863  break;
6864  case 'q':
6865  initialization_option_set = true;
6866  use_quiet = true;
6867  break;
6868  case 'r':
6869  benchmarking_option_set = true;
6870  report_per_command = true;
6871  break;
6872  case 'R':
6873  {
6874  /* get a double from the beginning of option value */
6875  double throttle_value = atof(optarg);
6876 
6877  benchmarking_option_set = true;
6878 
6879  if (throttle_value <= 0.0)
6880  pg_fatal("invalid rate limit: \"%s\"", optarg);
6881  /* Invert rate limit into per-transaction delay in usec */
6882  throttle_delay = 1000000.0 / throttle_value;
6883  }
6884  break;
6885  case 's':
6886  scale_given = true;
6887  if (!option_parse_int(optarg, "-s/--scale", 1, INT_MAX,
6888  &scale))
6889  exit(1);
6890  break;
6891  case 'S':
6892  process_builtin(findBuiltin("select-only"), 1);
6893  benchmarking_option_set = true;
6894  internal_script_used = true;
6895  break;
6896  case 't':
6897  benchmarking_option_set = true;
6898  if (!option_parse_int(optarg, "-t/--transactions", 1, INT_MAX,
6899  &nxacts))
6900  exit(1);
6901  break;
6902  case 'T':
6903  benchmarking_option_set = true;
6904  if (!option_parse_int(optarg, "-T/--time", 1, INT_MAX,
6905  &duration))
6906  exit(1);
6907  break;
6908  case 'U':
6910  break;
6911  case 'v':
6912  benchmarking_option_set = true;
6913  do_vacuum_accounts = true;
6914  break;
6915  case 1: /* unlogged-tables */
6916  initialization_option_set = true;
6917  unlogged_tables = true;
6918  break;
6919  case 2: /* tablespace */
6920  initialization_option_set = true;
6922  break;
6923  case 3: /* index-tablespace */
6924  initialization_option_set = true;
6926  break;
6927  case 4: /* sampling-rate */
6928  benchmarking_option_set = true;
6929  sample_rate = atof(optarg);
6930  if (sample_rate <= 0.0 || sample_rate > 1.0)
6931  pg_fatal("invalid sampling rate: \"%s\"", optarg);
6932  break;
6933  case 5: /* aggregate-interval */
6934  benchmarking_option_set = true;
6935  if (!option_parse_int(optarg, "--aggregate-interval", 1, INT_MAX,
6936  &agg_interval))
6937  exit(1);
6938  break;
6939  case 6: /* progress-timestamp */
6940  progress_timestamp = true;
6941  benchmarking_option_set = true;
6942  break;
6943  case 7: /* log-prefix */
6944  benchmarking_option_set = true;
6946  break;
6947  case 8: /* foreign-keys */
6948  initialization_option_set = true;
6949  foreign_keys = true;
6950  break;
6951  case 9: /* random-seed */
6952  benchmarking_option_set = true;
6953  if (!set_random_seed(optarg))
6954  pg_fatal("error while setting random seed from --random-seed option");
6955  break;
6956  case 10: /* list */
6957  {
6958  const BuiltinScript *s = findBuiltin(optarg);
6959 
6960  fprintf(stderr, "-- %s: %s\n%s\n", s->name, s->desc, s->script);
6961  exit(0);
6962  }
6963  break;
6964  case 11: /* partitions */
6965  initialization_option_set = true;
6966  if (!option_parse_int(optarg, "--partitions", 0, INT_MAX,
6967  &partitions))
6968  exit(1);
6969  break;
6970  case 12: /* partition-method */
6971  initialization_option_set = true;
6972  if (pg_strcasecmp(optarg, "range") == 0)
6974  else if (pg_strcasecmp(optarg, "hash") == 0)
6976  else
6977  pg_fatal("invalid partition method, expecting \"range\" or \"hash\", got: \"%s\"",
6978  optarg);
6979  break;
6980  case 13: /* failures-detailed */
6981  benchmarking_option_set = true;
6982  failures_detailed = true;
6983  break;
6984  case 14: /* max-tries */
6985  {
6986  int32 max_tries_arg = atoi(optarg);
6987 
6988  if (max_tries_arg < 0)
6989  pg_fatal("invalid number of maximum tries: \"%s\"", optarg);
6990 
6991  benchmarking_option_set = true;
6992  max_tries = (uint32) max_tries_arg;
6993  }
6994  break;
6995  case 15: /* verbose-errors */
6996  benchmarking_option_set = true;
6997  verbose_errors = true;
6998  break;
6999  case 16: /* exit-on-abort */
7000  benchmarking_option_set = true;
7001  exit_on_abort = true;
7002  break;
7003  case 17: /* debug */
7005  break;
7006  default:
7007  /* getopt_long already emitted a complaint */
7008  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7009  exit(1);
7010  }
7011  }
7012 
7013  /* set default script if none */
7014  if (num_scripts == 0 && !is_init_mode)
7015  {
7016  process_builtin(findBuiltin("tpcb-like"), 1);
7017  benchmarking_option_set = true;
7018  internal_script_used = true;
7019  }
7020 
7021  /* complete SQL command initialization and compute total weight */
7022  for (i = 0; i < num_scripts; i++)
7023  {
7024  Command **commands = sql_script[i].commands;
7025 
7026  for (int j = 0; commands[j] != NULL; j++)
7027  if (commands[j]->type == SQL_COMMAND)
7028  postprocess_sql_command(commands[j]);
7029 
7030  /* cannot overflow: weight is 32b, total_weight 64b */
7032  }
7033 
7034  if (total_weight == 0 && !is_init_mode)
7035  pg_fatal("total script weight must not be zero");
7036 
7037  /* show per script stats if several scripts are used */
7038  if (num_scripts > 1)
7039  per_script_stats = true;
7040 
7041  /*
7042  * Don't need more threads than there are clients. (This is not merely an
7043  * optimization; throttle_delay is calculated incorrectly below if some
7044  * threads have no clients assigned to them.)
7045  */
7046  if (nthreads > nclients)
7047  nthreads = nclients;
7048 
7049  /*
7050  * Convert throttle_delay to a per-thread delay time. Note that this
7051  * might be a fractional number of usec, but that's OK, since it's just
7052  * the center of a Poisson distribution of delays.
7053  */
7055 
7056  if (dbName == NULL)
7057  {
7058  if (argc > optind)
7059  dbName = argv[optind++];
7060  else
7061  {
7062  if ((env = getenv("PGDATABASE")) != NULL && *env != '\0')
7063  dbName = env;
7064  else if ((env = getenv("PGUSER")) != NULL && *env != '\0')
7065  dbName = env;
7066  else
7068  }
7069  }
7070 
7071  if (optind < argc)
7072  {
7073  pg_log_error("too many command-line arguments (first is \"%s\")",
7074  argv[optind]);
7075  pg_log_error_hint("Try \"%s --help\" for more information.", progname);
7076  exit(1);
7077  }
7078 
7079  if (is_init_mode)
7080  {
7081  if (benchmarking_option_set)
7082  pg_fatal("some of the specified options cannot be used in initialization (-i) mode");
7083 
7084  if (partitions == 0 && partition_method != PART_NONE)
7085  pg_fatal("--partition-method requires greater than zero --partitions");
7086 
7087  /* set default method */
7088  if (partitions > 0 && partition_method == PART_NONE)
7090 
7091  if (initialize_steps == NULL)
7092  initialize_steps = pg_strdup(DEFAULT_INIT_STEPS);
7093 
7094  if (is_no_vacuum)
7095  {
7096  /* Remove any vacuum step in initialize_steps */
7097  char *p;
7098 
7099  while ((p = strchr(initialize_steps, 'v')) != NULL)
7100  *p = ' ';
7101  }
7102 
7103  if (foreign_keys)
7104  {
7105  /* Add 'f' to end of initialize_steps, if not already there */
7106  if (strchr(initialize_steps, 'f') == NULL)
7107  {
7108  initialize_steps = (char *)
7109  pg_realloc(initialize_steps,
7110  strlen(initialize_steps) + 2);
7111  strcat(initialize_steps, "f");
7112  }
7113  }
7114 
7115  runInitSteps(initialize_steps);
7116  exit(0);
7117  }
7118  else
7119  {
7120  if (initialization_option_set)
7121  pg_fatal("some of the specified options cannot be used in benchmarking mode");
7122  }
7123 
7124  if (nxacts > 0 && duration > 0)
7125  pg_fatal("specify either a number of transactions (-t) or a duration (-T), not both");
7126 
7127  /* Use DEFAULT_NXACTS if neither nxacts nor duration is specified. */
7128  if (nxacts <= 0 && duration <= 0)
7130 
7131  /* --sampling-rate may be used only with -l */
7132  if (sample_rate > 0.0 && !use_log)
7133  pg_fatal("log sampling (--sampling-rate) is allowed only when logging transactions (-l)");
7134 
7135  /* --sampling-rate may not be used with --aggregate-interval */
7136  if (sample_rate > 0.0 && agg_interval > 0)
7137  pg_fatal("log sampling (--sampling-rate) and aggregation (--aggregate-interval) cannot be used at the same time");
7138 
7139  if (agg_interval > 0 && !use_log)
7140  pg_fatal("log aggregation is allowed only when actually logging transactions");
7141 
7142  if (!use_log && logfile_prefix)
7143  pg_fatal("log file prefix (--log-prefix) is allowed only when logging transactions (-l)");
7144 
7145  if (duration > 0 && agg_interval > duration)
7146  pg_fatal("number of seconds for aggregation (%d) must not be higher than test duration (%d)", agg_interval, duration);
7147 
7148  if (duration > 0 && agg_interval > 0 && duration % agg_interval != 0)
7149  pg_fatal("duration (%d) must be a multiple of aggregation interval (%d)", duration, agg_interval);
7150 
7151  if (progress_timestamp && progress == 0)
7152  pg_fatal("--progress-timestamp is allowed only under --progress");
7153 
7154  if (!max_tries)
7155  {
7156  if (!latency_limit && duration <= 0)
7157  pg_fatal("an unlimited number of transaction tries can only be used with --latency-limit or a duration (-T)");
7158  }
7159 
7160  /*
7161  * save main process id in the global variable because process id will be
7162  * changed after fork.
7163  */
7164  main_pid = (int) getpid();
7165 
7166  if (nclients > 1)
7167  {
7168  state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
7169  memset(state + 1, 0, sizeof(CState) * (nclients - 1));
7170 
7171  /* copy any -D switch values to all clients */
7172  for (i = 1; i < nclients; i++)
7173  {
7174  int j;
7175 
7176  state[i].id = i;
7177  for (j = 0; j < state[0].variables.nvars; j++)
7178  {
7179  Variable *var = &state[0].variables.vars[j];
7180 
7181  if (var->value.type != PGBT_NO_VALUE)
7182  {
7183  if (!putVariableValue(&state[i].variables, "startup",
7184  var->name, &var->value))
7185  exit(1);
7186  }
7187  else
7188  {
7189  if (!putVariable(&state[i].variables, "startup",
7190  var->name, var->svalue))
7191  exit(1);
7192  }
7193  }
7194  }
7195  }
7196 
7197  /* other CState initializations */
7198  for (i = 0; i < nclients; i++)
7199  {
7200  state[i].cstack = conditional_stack_create();
7201  initRandomState(&state[i].cs_func_rs);
7202  }
7203 
7204  /* opening connection... */
7205  con = doConnect();
7206  if (con == NULL)
7207  pg_fatal("could not create connection for setup");
7208 
7209  /* report pgbench and server versions */
7210  printVersion(con);
7211 
7212  pg_log_debug("pghost: %s pgport: %s nclients: %d %s: %d dbName: %s",
7213  PQhost(con), PQport(con), nclients,
7214  duration <= 0 ? "nxacts" : "duration",
7215  duration <= 0 ? nxacts : duration, PQdb(con));
7216 
7217  if (internal_script_used)
7218  GetTableInfo(con, scale_given);
7219 
7220  /*
7221  * :scale variables normally get -s or database scale, but don't override
7222  * an explicit -D switch
7223  */
7224  if (lookupVariable(&state[0].variables, "scale") == NULL)
7225  {
7226  for (i = 0; i < nclients; i++)
7227  {
7228  if (!putVariableInt(&state[i].variables, "startup", "scale", scale))
7229  exit(1);
7230  }
7231  }
7232 
7233  /*
7234  * Define a :client_id variable that is unique per connection. But don't
7235  * override an explicit -D switch.
7236  */
7237  if (lookupVariable(&state[0].variables, "client_id") == NULL)
7238  {
7239  for (i = 0; i < nclients; i++)
7240  if (!putVariableInt(&state[i].variables, "startup", "client_id", i))
7241  exit(1);
7242  }
7243 
7244  /* set default seed for hash functions */
7245  if (lookupVariable(&state[0].variables, "default_seed") == NULL)
7246  {
7247  uint64 seed = pg_prng_uint64(&base_random_sequence);
7248 
7249  for (i = 0; i < nclients; i++)
7250  if (!putVariableInt(&state[i].variables, "startup", "default_seed",
7251  (int64) seed))
7252  exit(1);
7253  }
7254 
7255  /* set random seed unless overwritten */
7256  if (lookupVariable(&state[0].variables, "random_seed") == NULL)
7257  {
7258  for (i = 0; i < nclients; i++)
7259  if (!putVariableInt(&state[i].variables, "startup", "random_seed",
7260  random_seed))
7261  exit(1);
7262  }
7263 
7264  if (!is_no_vacuum)
7265  {
7266  fprintf(stderr, "starting vacuum...");
7267  tryExecuteStatement(con, "vacuum pgbench_branches");
7268  tryExecuteStatement(con, "vacuum pgbench_tellers");
7269  tryExecuteStatement(con, "truncate pgbench_history");
7270  fprintf(stderr, "end.\n");
7271 
7272  if (do_vacuum_accounts)
7273  {
7274  fprintf(stderr, "starting vacuum pgbench_accounts...");
7275  tryExecuteStatement(con, "vacuum analyze pgbench_accounts");
7276  fprintf(stderr, "end.\n");
7277  }
7278  }
7279  PQfinish(con);
7280 
7281  /* set up thread data structures */
7282  threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
7283  nclients_dealt = 0;
7284 
7285  for (i = 0; i < nthreads; i++)
7286  {
7287  TState *thread = &threads[i];
7288 
7289  thread->tid = i;
7290  thread->state = &state[nclients_dealt];
7291  thread->nstate =
7292  (nclients - nclients_dealt + nthreads - i - 1) / (nthreads - i);
7293  initRandomState(&thread->ts_choose_rs);
7294  initRandomState(&thread->ts_throttle_rs);
7295  initRandomState(&thread->ts_sample_rs);
7296  thread->logfile = NULL; /* filled in later */
7297  thread->latency_late = 0;
7298  initStats(&thread->stats, 0);
7299 
7300  nclients_dealt += thread->nstate;
7301  }
7302 
7303  /* all clients must be assigned to a thread */
7304  Assert(nclients_dealt == nclients);
7305 
7306  /* get start up time for the whole computation */
7307  start_time = pg_time_now();
7308 
7309  /* set alarm if duration is specified. */
7310  if (duration > 0)
7311  setalarm(duration);
7312 
7314  if (errno != 0)
7315  pg_fatal("could not initialize barrier: %m");
7316 
7317  /* start all threads but thread 0 which is executed directly later */
7318  for (i = 1; i < nthreads; i++)
7319  {
7320  TState *thread = &threads[i];
7321 
7322  thread->create_time = pg_time_now();
7323  errno = THREAD_CREATE(&thread->thread, threadRun, thread);
7324 
7325  if (errno != 0)
7326  pg_fatal("could not create thread: %m");
7327  }
7328 
7329  /* compute when to stop */
7330  threads[0].create_time = pg_time_now();
7331  if (duration > 0)
7332  end_time = threads[0].create_time + (int64) 1000000 * duration;
7333 
7334  /* run thread 0 directly */
7335  (void) threadRun(&threads[0]);
7336 
7337  /* wait for other threads and accumulate results */
7338  initStats(&stats, 0);
7339  conn_total_duration = 0;
7340 
7341  for (i = 0; i < nthreads; i++)
7342  {
7343  TState *thread = &threads[i];
7344 
7345  if (i > 0)
7346  THREAD_JOIN(thread->thread);
7347 
7348  for (int j = 0; j < thread->nstate; j++)
7349  if (thread->state[j].state != CSTATE_FINISHED)
7350  exit_code = 2;
7351 
7352  /* aggregate thread level stats */
7353  mergeSimpleStats(&stats.latency, &thread->stats.latency);
7354  mergeSimpleStats(&stats.lag, &thread->stats.lag);
7355  stats.cnt += thread->stats.cnt;
7356  stats.skipped += thread->stats.skipped;
7357  stats.retries += thread->stats.retries;
7358  stats.retried += thread->stats.retried;
7360  stats.deadlock_failures += thread->stats.deadlock_failures;
7361  latency_late += thread->latency_late;
7362  conn_total_duration += thread->conn_duration;
7363 
7364  /* first recorded benchmarking start time */
7365  if (bench_start == 0 || thread->bench_start < bench_start)
7366  bench_start = thread->bench_start;
7367  }
7368 
7369  /*
7370  * All connections should be already closed in threadRun(), so this
7371  * disconnect_all() will be a no-op, but clean up the connections just to
7372  * be sure. We don't need to measure the disconnection delays here.
7373  */
7375 
7376  /*
7377  * Beware that performance of short benchmarks with many threads and
7378  * possibly long transactions can be deceptive because threads do not
7379  * start and finish at the exact same time. The total duration computed
7380  * here encompasses all transactions so that tps shown is somehow slightly
7381  * underestimated.
7382  */
7383  printResults(&stats, pg_time_now() - bench_start, conn_total_duration,
7384  bench_start - start_time, latency_late);
7385 
7387 
7388  if (exit_code != 0)
7389  pg_log_error("Run was aborted; the above results are incomplete.");
7390 
7391  return exit_code;
unsigned int uint32
Definition: c.h:506
char * PQhost(const PGconn *conn)
Definition: fe-connect.c:7026
char * PQport(const PGconn *conn)
Definition: fe-connect.c:7062
int getopt_long(int argc, char *const argv[], const char *optstring, const struct option *longopts, int *longindex)
Definition: getopt_long.c:60
#define no_argument
Definition: getopt_long.h:24
#define required_argument
Definition: getopt_long.h:25
void pg_logging_increase_verbosity(void)
Definition: logging.c:182
void pg_logging_init(const char *argv0)
Definition: logging.c:83
bool option_parse_int(const char *optarg, const char *optname, int min_range, int max_range, int *result)
Definition: option_utils.c:50
static time_t start_time
Definition: pg_ctl.c:94
PGDLLIMPORT int optind
Definition: getopt.c:50
PGDLLIMPORT char * optarg
Definition: getopt.c:52
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)
Definition: pgbench.c:6352
static bool putVariableInt(Variables *variables, const char *context, char *name, int64 value)
Definition: pgbench.c:1870
static void GetTableInfo(PGconn *con, bool scale_given)
Definition: pgbench.c:5307
static void initRandomState(pg_prng_state *state)
Definition: pgbench.c:1087
bool per_script_stats
Definition: pgbench.c:260
static const BuiltinScript * findBuiltin(const char *name)
Definition: pgbench.c:6119
static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun(void *arg)
Definition: pgbench.c:7394
static void setalarm(int seconds)
Definition: pgbench.c:7716
int nthreads
Definition: pgbench.c:264
static bool exit_on_abort
Definition: pgbench.c:769
static bool putVariable(Variables *variables, const char *context, char *name, const char *value)
Definition: pgbench.c:1828
int nclients
Definition: pgbench.c:263
static void printVersion(PGconn *con)
Definition: pgbench.c:6321
#define DEFAULT_NXACTS
Definition: pgbench.c:166
static void checkInitSteps(const char *initialize_steps)
Definition: pgbench.c:5202
int progress
Definition: pgbench.c:261
static void postprocess_sql_command(Command *my_command)
Definition: pgbench.c:5597
bool progress_timestamp
Definition: pgbench.c:262
static const char *const QUERYMODE[]
Definition: pgbench.c:713
static void mergeSimpleStats(SimpleStats *acc, SimpleStats *ss)
Definition: pgbench.c:1417
#define THREAD_JOIN(handle)
Definition: pgbench.c:149
char * logfile_prefix
Definition: pgbench.c:298
static bool set_random_seed(const char *seed)
Definition: pgbench.c:6570
static void runInitSteps(const char *initialize_steps)
Definition: pgbench.c:5222
static void process_builtin(const BuiltinScript *bi, int weight)
Definition: pgbench.c:6100
static int parseScriptWeight(const char *option, char **script)
Definition: pgbench.c:6155
static void tryExecuteStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1515
static THREAD_BARRIER_T barrier
Definition: pgbench.c:479
static void process_file(const char *filename, int weight)
Definition: pgbench.c:6074
int main_pid
Definition: pgbench.c:269
#define THREAD_BARRIER_INIT(barrier, n)
Definition: pgbench.c:152
static void usage(void)
Definition: pgbench.c:869
static void disconnect_all(CState *state, int length)
Definition: pgbench.c:4704
#define DEFAULT_INIT_STEPS
Definition: pgbench.c:162
int64 random_seed
Definition: pgbench.c:237
#define THREAD_CREATE(handle, function, arg)
Definition: pgbench.c:147
#define THREAD_BARRIER_DESTROY(barrier)
Definition: pgbench.c:155
const char * get_progname(const char *argv0)
Definition: path.c:574
char * c
const char * desc
Definition: pgbench.c:775
const char * name
Definition: pgbench.c:774
const char * script
Definition: pgbench.c:776
pg_time_usec_t create_time
Definition: pgbench.c:664
CState * state
Definition: pgbench.c:648
int tid
Definition: pgbench.c:646
int nstate
Definition: pgbench.c:649
StatsData stats
Definition: pgbench.c:670
THREAD_T thread
Definition: pgbench.c:647
pg_time_usec_t bench_start
Definition: pgbench.c:666
int64 latency_late
Definition: pgbench.c:671
const char * get_user_name_or_exit(const char *progname)
Definition: username.c:74
int gettimeofday(struct timeval *tp, void *tzp)

References agg_interval, Assert, barrier, base_random_sequence, TState::bench_start, checkInitSteps(), StatsData::cnt, ParsedScript::commands, conditional_stack_create(), TState::conn_duration, TState::create_time, CSTATE_FINISHED, dbName, StatsData::deadlock_failures, DEFAULT_INIT_STEPS, DEFAULT_NXACTS, BuiltinScript::desc, disconnect_all(), doConnect(), duration, end_time, epoch_shift, exit(), exit_on_abort, failures_detailed, fillfactor, findBuiltin(), fprintf, get_progname(), get_user_name_or_exit(), getopt_long(), GetTableInfo(), gettimeofday(), i, index_tablespace, initRandomState(), initStats(), is_connect, j, StatsData::lag, StatsData::latency, TState::latency_late, latency_limit, listAvailableScripts(), TState::logfile, logfile_prefix, lookupVariable(), main_pid, max_tries, mergeSimpleStats(), Variable::name, BuiltinScript::name, nclients, no_argument, TState::nstate, nthreads, NUM_QUERYMODE, num_scripts, nxacts, optarg, optind, option_parse_int(), parseScriptWeight(), PART_HASH, PART_NONE, PART_RANGE, partition_method, partitions, per_script_stats, pg_fatal, pg_free(), pg_log_debug, pg_log_error, pg_log_error_hint, pg_logging_increase_verbosity(), pg_logging_init(), pg_malloc(), pg_malloc0(), pg_prng_uint64(), pg_realloc(), pg_strcasecmp(), pg_strdup(), pg_time_now(), PGBT_NO_VALUE, pghost, pgport, postprocess_sql_command(), PQdb(), PQfinish(), PQhost(), PQport(), printResults(), printVersion(), process_builtin(), process_file(), progname, progress, progress_timestamp, putVariable(), putVariableInt(), putVariableValue(), querymode, QUERYMODE, random_seed, report_per_command, required_argument, StatsData::retried, StatsData::retries, runInitSteps(), sample_rate, scale, BuiltinScript::script, StatsData::serialization_failures, set_random_seed(), setalarm(), StatsData::skipped, SQL_COMMAND, sql_script, start_time, CState::state, TState::state, TState::stats, Variable::svalue, tablespace, TState::thread, THREAD_BARRIER_DESTROY, THREAD_BARRIER_INIT, THREAD_CREATE, THREAD_JOIN, threadRun(), throttle_delay, TState::tid, total_weight, tryExecuteStatement(), TState::ts_choose_rs, TState::ts_sample_rs, TState::ts_throttle_rs, type, PgBenchValue::type, unlogged_tables, usage(), use_log, use_quiet, username, Variable::value, verbose_errors, and ParsedScript::weight.

◆ makeVariableValue()

static bool makeVariableValue ( Variable var)
static

Definition at line 1663 of file pgbench.c.

1665 {
1666  size_t slen;
1667 
1668  if (var->value.type != PGBT_NO_VALUE)
1669  return true; /* no work */
1670 
1671  slen = strlen(var->svalue);
1672 
1673  if (slen == 0)
1674  /* what should it do on ""? */
1675  return false;
1676 
1677  if (pg_strcasecmp(var->svalue, "null") == 0)
1678  {
1679  setNullValue(&var->value);
1680  }
1681 
1682  /*
1683  * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1684  * recognized later as an int, which is converted to bool if needed.
1685  */
1686  else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1687  pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1688  pg_strcasecmp(var->svalue, "on") == 0)
1689  {
1690  setBoolValue(&var->value, true);
1691  }
1692  else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1693  pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1694  pg_strcasecmp(var->svalue, "off") == 0 ||
1695  pg_strcasecmp(var->svalue, "of") == 0)
1696  {
1697  setBoolValue(&var->value, false);
1698  }
1699  else if (is_an_int(var->svalue))
1700  {
1701  /* if it looks like an int, it must be an int without overflow */
1702  int64 iv;
1703 
1704  if (!strtoint64(var->svalue, false, &iv))
1705  return false;
1706 
1707  setIntValue(&var->value, iv);
1708  }
1709  else /* type should be double */
1710  {
1711  double dv;
1712 
1713  if (!strtodouble(var->svalue, true, &dv))
1714  {
1715  pg_log_error("malformed variable \"%s\" value: \"%s\"",
1716  var->name, var->svalue);
1717  return false;
1718  }
1719  setDoubleValue(&var->value, dv);
1720  }
1721  return true;
bool strtodouble(const char *str, bool errorOK, double *dv)
Definition: pgbench.c:1058
bool strtoint64(const char *str, bool errorOK, int64 *result)
Definition: pgbench.c:987
static bool is_an_int(const char *str)
Definition: pgbench.c:950
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69

References is_an_int(), Variable::name, pg_log_error, pg_strcasecmp(), pg_strncasecmp(), PGBT_NO_VALUE, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), strtodouble(), strtoint64(), Variable::svalue, PgBenchValue::type, and Variable::value.

Referenced by evaluateExpr().

◆ mergeSimpleStats()

static void mergeSimpleStats ( SimpleStats acc,
SimpleStats ss 
)
static

Definition at line 1417 of file pgbench.c.

1419 {
1420  if (acc->count == 0 || ss->min < acc->min)
1421  acc->min = ss->min;
1422  if (acc->count == 0 || ss->max > acc->max)
1423  acc->max = ss->max;
1424  acc->count += ss->count;
1425  acc->sum += ss->sum;
1426  acc->sum2 += ss->sum2;

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

Referenced by main(), and printProgressReport().

◆ parseQuery()

static bool parseQuery ( Command cmd)
static

Definition at line 5416 of file pgbench.c.

5418 {
5419  char *sql,
5420  *p;
5421 
5422  cmd->argc = 1;
5423 
5424  p = sql = pg_strdup(cmd->lines.data);
5425  while ((p = strchr(p, ':')) != NULL)
5426  {
5427  char var[13];
5428  char *name;
5429  int eaten;
5430 
5431  name = parseVariable(p, &eaten);
5432  if (name == NULL)
5433  {
5434  while (*p == ':')
5435  {
5436  p++;
5437  }
5438  continue;
5439  }
5440 
5441  /*
5442  * cmd->argv[0] is the SQL statement itself, so the max number of
5443  * arguments is one less than MAX_ARGS
5444  */
5445  if (cmd->argc >= MAX_ARGS)
5446  {
5447  pg_log_error("statement has too many arguments (maximum is %d): %s",
5448  MAX_ARGS - 1, cmd->lines.data);
5449  pg_free(name);
5450  return false;
5451  }
5452 
5453  sprintf(var, "$%d", cmd->argc);
5454  p = replaceVariable(&sql, p, eaten, var);
5455 
5456  cmd->argv[cmd->argc] = name;
5457  cmd->argc++;
5458  }
5459 
5460  Assert(cmd->argv[0] == NULL);
5461  cmd->argv[0] = sql;
5462  return true;
#define MAX_ARGS
Definition: pgbench.c:684
#define sprintf
Definition: port.h:240

References Command::argc, Command::argv, Assert, PQExpBufferData::data, Command::lines, MAX_ARGS, name, parseVariable(), pg_free(), pg_log_error, pg_strdup(), replaceVariable(), and sprintf.

Referenced by postprocess_sql_command().

◆ ParseScript()

static void ParseScript ( const char *  script,
const char *  desc,
int  weight 
)
static

Definition at line 5904 of file pgbench.c.

5906 {
5907  ParsedScript ps;
5908  PsqlScanState sstate;
5909  PQExpBufferData line_buf;
5910  int alloc_num;
5911  int index;
5912  int lineno;
5913  int start_offset;
5914 
5915 #define COMMANDS_ALLOC_NUM 128
5916  alloc_num = COMMANDS_ALLOC_NUM;
5917 
5918  /* Initialize all fields of ps */
5919  ps.desc = desc;
5920  ps.weight = weight;
5921  ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
5922  initStats(&ps.stats, 0);
5923 
5924  /* Prepare to parse script */
5926 
5927  /*
5928  * Ideally, we'd scan scripts using the encoding and stdstrings settings
5929  * we get from a DB connection. However, without major rearrangement of
5930  * pgbench's argument parsing, we can't have a DB connection at the time
5931  * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5932  * with any backend-safe encoding, though conceivably we could be fooled
5933  * if a script file uses a client-only encoding. We also assume that
5934  * stdstrings should be true, which is a bit riskier.
5935  */
5936  psql_scan_setup(sstate, script, strlen(script), 0, true);
5937  start_offset = expr_scanner_offset(sstate) - 1;
5938 
5939  initPQExpBuffer(&line_buf);
5940 
5941  index = 0;
5942 
5943  for (;;)
5944  {
5945  PsqlScanResult sr;
5946  promptStatus_t prompt;
5947  Command *command = NULL;
5948 
5949  resetPQExpBuffer(&line_buf);
5950  lineno = expr_scanner_get_lineno(sstate, start_offset);
5951 
5952  sr = psql_scan(sstate, &line_buf, &prompt);
5953 
5954  /* If we collected a new SQL command, process that */
5955  command = create_sql_command(&line_buf, desc);
5956 
5957  /* store new command */
5958  if (command)
5959  ps.commands[index++] = command;
5960 
5961  /* If we reached a backslash, process that */
5962  if (sr == PSCAN_BACKSLASH)
5963  {
5964  command = process_backslash_command(sstate, desc);
5965 
5966  if (command)
5967  {
5968  /*
5969  * If this is gset or aset, merge into the preceding command.
5970  * (We don't use a command slot in this case).
5971  */
5972  if (command->meta == META_GSET || command->meta == META_ASET)
5973  {
5974  Command *cmd;
5975 
5976  if (index == 0)
5977  syntax_error(desc, lineno, NULL, NULL,
5978  "\\gset must follow an SQL command",
5979  NULL, -1);
5980 
5981  cmd = ps.commands[index - 1];
5982 
5983  if (cmd->type != SQL_COMMAND ||
5984  cmd->varprefix != NULL)
5985  syntax_error(desc, lineno, NULL, NULL,
5986  "\\gset must follow an SQL command",
5987  cmd->first_line, -1);
5988 
5989  /* get variable prefix */
5990  if (command->argc <= 1 || command->argv[1][0] == '\0')
5991  cmd->varprefix = pg_strdup("");
5992  else
5993  cmd->varprefix = pg_strdup(command->argv[1]);
5994 
5995  /* update the sql command meta */
5996  cmd->meta = command->meta;
5997 
5998  /* cleanup unused command */
5999  free_command(command);
6000 
6001  continue;
6002  }
6003 
6004  /* Attach any other backslash command as a new command */
6005  ps.commands[index++] = command;
6006  }
6007  }
6008 
6009  /*
6010  * Since we used a command slot, allocate more if needed. Note we
6011  * always allocate one more in order to accommodate the NULL
6012  * terminator below.
6013  */
6014  if (index >= alloc_num)
6015  {
6016  alloc_num += COMMANDS_ALLOC_NUM;
6017  ps.commands = (Command **)
6018  pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
6019  }
6020 
6021  /* Done if we reached EOF */
6022  if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
6023  break;
6024  }
6025 
6026  ps.commands[index] = NULL;
6027 
6028  addScript(&ps);
6029 
6030  termPQExpBuffer(&line_buf);
6031  psql_scan_finish(sstate);
6032  psql_scan_destroy(sstate);
void syntax_error(const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
Definition: pgbench.c:5477
#define COMMANDS_ALLOC_NUM
static void free_command(Command *command)
Definition: pgbench.c:5577
static Command * process_backslash_command(PsqlScanState sstate, const char *source)
Definition: pgbench.c:5634
static void addScript(const ParsedScript *script)
Definition: pgbench.c:6192
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:845
static Command * create_sql_command(PQExpBuffer buf, const char *source)
Definition: pgbench.c:5548
int expr_scanner_offset(PsqlScanState state)
int expr_scanner_get_lineno(PsqlScanState state, int offset)
PsqlScanResult
Definition: psqlscan.h:31
@ PSCAN_BACKSLASH
Definition: psqlscan.h:33
@ PSCAN_EOL
Definition: psqlscan.h:35
@ PSCAN_INCOMPLETE
Definition: psqlscan.h:34
enum _promptStatus promptStatus_t
void psql_scan_destroy(PsqlScanState state)
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
void psql_scan_finish(PsqlScanState state)
Definition: type.h:95

References addScript(), Command::argc, Command::argv, COMMANDS_ALLOC_NUM, create_sql_command(), expr_scanner_get_lineno(), expr_scanner_offset(), Command::first_line, free_command(), initPQExpBuffer(), initStats(), Command::meta, META_ASET, META_GSET, pg_malloc(), pg_realloc(), pg_strdup(), pgbench_callbacks, process_backslash_command(), ps, PSCAN_BACKSLASH, PSCAN_EOL, PSCAN_INCOMPLETE, psql_scan(), psql_scan_create(), psql_scan_destroy(), psql_scan_finish(), psql_scan_setup(), resetPQExpBuffer(), SQL_COMMAND, syntax_error(), termPQExpBuffer(), Command::type, and Command::varprefix.

Referenced by process_builtin(), and process_file().

◆ parseScriptWeight()

static int parseScriptWeight ( const char *  option,
char **  script 
)
static

Definition at line 6155 of file pgbench.c.

6157 {
6158  char *sep;
6159  int weight;
6160 
6161  if ((sep = strrchr(option, WSEP)))
6162  {
6163  int namelen = sep - option;
6164  long wtmp;
6165  char *badp;
6166 
6167  /* generate the script name */
6168  *script = pg_malloc(namelen + 1);
6169  strncpy(*script, option, namelen);
6170  (*script)[namelen] = '\0';
6171 
6172  /* process digits of the weight spec */
6173  errno = 0;
6174  wtmp = strtol(sep + 1, &badp, 10);
6175  if (errno != 0 || badp == sep + 1 || *badp != '\0')
6176  pg_fatal("invalid weight specification: %s", sep);
6177  if (wtmp > INT_MAX || wtmp < 0)
6178  pg_fatal("weight specification out of range (0 .. %d): %lld",
6179  INT_MAX, (long long) wtmp);
6180  weight = wtmp;
6181  }
6182  else
6183  {
6184  *script = pg_strdup(option);
6185  weight = 1;
6186  }
6187 
6188  return weight;
#define WSEP
Definition: pgbench.c:301

References pg_fatal, pg_malloc(), pg_strdup(), and WSEP.

Referenced by main().

◆ parseVariable()

static char* parseVariable ( const char *  sql,
int *  eaten 
)
static

Definition at line 1888 of file pgbench.c.

1890 {
1891  int i = 1; /* starting at 1 skips the colon */
1892  char *name;
1893 
1894  /* keep this logic in sync with valid_variable_name() */
1895  if (IS_HIGHBIT_SET(sql[i]) ||
1896  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1897  "_", sql[i]) != NULL)
1898  i++;
1899  else
1900  return NULL;
1901 
1902  while (IS_HIGHBIT_SET(sql[i]) ||
1903  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1904  "_0123456789", sql[i]) != NULL)
1905  i++;
1906 
1907  name = pg_malloc(i);
1908  memcpy(name, &sql[1], i - 1);
1909  name[i - 1] = '\0';
1910 
1911  *eaten = i;
1912  return name;
#define IS_HIGHBIT_SET(ch)
Definition: c.h:1155

References i, IS_HIGHBIT_SET, name, and pg_malloc().

Referenced by assignVariables(), and parseQuery().

◆ permute()

static int64 permute ( const int64  val,
const int64  isize,
const int64  seed 
)
static

Definition at line 1302 of file pgbench.c.

1304 {
1305  /* using a high-end PRNG is probably overkill */
1307  uint64 size;
1308  uint64 v;
1309  int masklen;
1310  uint64 mask;
1311  int i;
1312 
1313  if (isize < 2)
1314  return 0; /* nothing to permute */
1315 
1316  /* Initialize prng state using the seed */
1317  pg_prng_seed(&state, (uint64) seed);
1318 
1319  /* Computations are performed on unsigned values */
1320  size = (uint64) isize;
1321  v = (uint64) val % size;
1322 
1323  /* Mask to work modulo largest power of 2 less than or equal to size */
1324  masklen = pg_leftmost_one_pos64(size);
1325  mask = (((uint64) 1) << masklen) - 1;
1326 
1327  /*
1328  * Permute the input value by applying several rounds of pseudorandom
1329  * bijective transformations. The intention here is to distribute each
1330  * input uniformly randomly across the range, and separate adjacent inputs
1331  * approximately uniformly randomly from each other, leading to a fairly
1332  * random overall choice of permutation.
1333  *
1334  * To separate adjacent inputs, we multiply by a random number modulo
1335  * (mask + 1), which is a power of 2. For this to be a bijection, the
1336  * multiplier must be odd. Since this is known to lead to less randomness
1337  * in the lower bits, we also apply a rotation that shifts the topmost bit
1338  * into the least significant bit. In the special cases where size <= 3,
1339  * mask = 1 and each of these operations is actually a no-op, so we also
1340  * XOR the value with a different random number to inject additional
1341  * randomness. Since the size is generally not a power of 2, we apply
1342  * this bijection on overlapping upper and lower halves of the input.
1343  *
1344  * To distribute the inputs uniformly across the range, we then also apply
1345  * a random offset modulo the full range.
1346  *
1347  * Taken together, these operations resemble a modified linear
1348  * congruential generator, as is commonly used in pseudorandom number
1349  * generators. The number of rounds is fairly arbitrary, but six has been
1350  * found empirically to give a fairly good tradeoff between performance
1351  * and uniform randomness. For small sizes it selects each of the (size!)
1352  * possible permutations with roughly equal probability. For larger
1353  * sizes, not all permutations can be generated, but the intended random
1354  * spread is still produced.
1355  */
1356  for (i = 0; i < 6; i++)
1357  {
1358  uint64 m,
1359  r,
1360  t;
1361 
1362  /* Random multiply (by an odd number), XOR and rotate of lower half */
1363  m = (pg_prng_uint64(&state) & mask) | 1;
1364  r = pg_prng_uint64(&state) & mask;
1365  if (v <= mask)
1366  {
1367  v = ((v * m) ^ r) & mask;
1368  v = ((v << 1) & mask) | (v >> (masklen - 1));
1369  }
1370 
1371  /* Random multiply (by an odd number), XOR and rotate of upper half */
1372  m = (pg_prng_uint64(&state) & mask) | 1;
1373  r = pg_prng_uint64(&state) & mask;
1374  t = size - 1 - v;
1375  if (t <= mask)
1376  {
1377  t = ((t * m) ^ r) & mask;
1378  t = ((t << 1) & mask) | (t >> (masklen - 1));
1379  v = size - 1 - t;
1380  }
1381 
1382  /* Random offset */
1383  r = pg_prng_uint64_range(&state, 0, size - 1);
1384  v = (v + r) % size;
1385  }
1386 
1387  return (int64) v;
static int pg_leftmost_one_pos64(uint64 word)
Definition: pg_bitutils.h:72

References i, pg_leftmost_one_pos64(), pg_prng_seed(), pg_prng_uint64(), pg_prng_uint64_range(), size, and val.

Referenced by evalStandardFunc().

◆ pg_time_now()

static pg_time_usec_t pg_time_now ( void  )
inlinestatic

Definition at line 850 of file pgbench.c.

852 {
853  instr_time now;
854 
856 
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:122
#define INSTR_TIME_GET_MICROSEC(t)
Definition: instr_time.h:194

References INSTR_TIME_GET_MICROSEC, INSTR_TIME_SET_CURRENT, and now().

Referenced by advanceConnectionState(), doLog(), initPopulateTable(), main(), pg_time_now_lazy(), runInitSteps(), set_random_seed(), and threadRun().

◆ pg_time_now_lazy()

static void pg_time_now_lazy ( pg_time_usec_t now)
inlinestatic

Definition at line 860 of file pgbench.c.

862 {
863  if ((*now) == 0)
864  (*now) = pg_time_now();

References now(), and pg_time_now().

Referenced by advanceConnectionState(), doRetry(), executeMetaCommand(), printVerboseErrorMessages(), processXactStats(), and threadRun().

◆ postprocess_sql_command()

static void postprocess_sql_command ( Command my_command)
static

Definition at line 5597 of file pgbench.c.

5599 {
5600  char buffer[128];
5601  static int prepnum = 0;
5602 
5603  Assert(my_command->type == SQL_COMMAND);
5604 
5605  /* Save the first line for error display. */
5606  strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5607  buffer[strcspn(buffer, "\n\r")] = '\0';
5608  my_command->first_line = pg_strdup(buffer);
5609 
5610  /* Parse query and generate prepared statement name, if necessary */
5611  switch (querymode)
5612  {
5613  case QUERY_SIMPLE:
5614  my_command->argv[0] = my_command->lines.data;
5615  my_command->argc++;
5616  break;
5617  case QUERY_PREPARED:
5618  my_command->prepname = psprintf("P_%d", prepnum++);
5619  /* fall through */
5620  case QUERY_EXTENDED:
5621  if (!parseQuery(my_command))
5622  exit(1);
5623  break;
5624  default:
5625  exit(1);
5626  }
static bool parseQuery(Command *cmd)
Definition: pgbench.c:5416
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46

References Command::argc, Command::argv, Assert, PQExpBufferData::data, exit(), Command::first_line, Command::lines, parseQuery(), pg_strdup(), Command::prepname, psprintf(), QUERY_EXTENDED, QUERY_PREPARED, QUERY_SIMPLE, querymode, SQL_COMMAND, strlcpy(), and Command::type.

Referenced by main().

◆ prepareCommand()

static void prepareCommand ( CState st,
int  command_num 
)
static

Definition at line 3088 of file pgbench.c.

3090 {
3091  Command *command = sql_script[st->use_file].commands[command_num];
3092 
3093  /* No prepare for non-SQL commands */
3094  if (command->type != SQL_COMMAND)
3095  return;
3096 
3097  if (!st->prepared)
3098  allocCStatePrepared(st);
3099 
3100  if (!st->prepared[st->use_file][command_num])
3101  {
3102  PGresult *res;
3103 
3104  pg_log_debug("client %d preparing %s", st->id, command->prepname);
3105  res = PQprepare(st->con, command->prepname,
3106  command->argv[0], command->argc - 1, NULL);
3108  pg_log_error("%s", PQerrorMessage(st->con));
3109  PQclear(res);
3110  st->prepared[st->use_file][command_num] = true;
3111  }
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:2306
static void allocCStatePrepared(CState *st)
Definition: pgbench.c:3068

References allocCStatePrepared(), Command::argc, Command::argv, ParsedScript::commands, CState::con, CState::id, pg_log_debug, pg_log_error, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQprepare(), PQresultStatus(), CState::prepared, Command::prepname, res, SQL_COMMAND, sql_script, Command::type, and CState::use_file.

Referenced by prepareCommandsInPipeline(), and sendCommand().

◆ prepareCommandsInPipeline()

static void prepareCommandsInPipeline ( CState st)
static

Definition at line 3121 of file pgbench.c.

3123 {
3124  int j;
3125  Command **commands = sql_script[st->use_file].commands;
3126 
3127  Assert(commands[st->command]->type == META_COMMAND &&
3128  commands[st->command]->meta == META_STARTPIPELINE);
3129 
3130  if (!st->prepared)
3131  allocCStatePrepared(st);
3132 
3133  /*
3134  * We set the 'prepared' flag on the \startpipeline itself to flag that we
3135  * don't need to do this next time without calling prepareCommand(), even
3136  * though we don't actually prepare this command.
3137  */
3138  if (st->prepared[st->use_file][st->command])
3139  return;
3140 
3141  for (j = st->command + 1; commands[j] != NULL; j++)
3142  {
3143  if (commands[j]->type == META_COMMAND &&
3144  commands[j]->meta == META_ENDPIPELINE)
3145  break;
3146 
3147  prepareCommand(st, j);
3148  }
3149 
3150  st->prepared[st->use_file][st->command] = true;
static void prepareCommand(CState *st, int command_num)
Definition: pgbench.c:3088

References allocCStatePrepared(), Assert, CState::command, ParsedScript::commands, j, Command::meta, META_COMMAND, META_ENDPIPELINE, META_STARTPIPELINE, prepareCommand(), CState::prepared, sql_script, type, Command::type, and CState::use_file.

Referenced by executeMetaCommand().

◆ printProgressReport()

static void printProgressReport ( TState threads,
int64  test_start,
pg_time_usec_t  now,
StatsData last,
int64 *  last_report 
)
static

Definition at line 6213 of file pgbench.c.

6216 {
6217  /* generate and show report */
6218  pg_time_usec_t run = now - *last_report;
6219  int64 cnt,
6220  failures,
6221  retried;
6222  double tps,
6223  total_run,
6224  latency,
6225  sqlat,
6226  lag,
6227  stdev;
6228  char tbuf[315];
6229  StatsData cur;
6230 
6231  /*
6232  * Add up the statistics of all threads.
6233  *
6234  * XXX: No locking. There is no guarantee that we get an atomic snapshot
6235  * of the transaction count and latencies, so these figures can well be
6236  * off by a small amount. The progress report's purpose is to give a
6237  * quick overview of how the test is going, so that shouldn't matter too
6238  * much. (If a read from a 64-bit integer is not atomic, you might get a
6239  * "torn" read and completely bogus latencies though!)
6240  */
6241  initStats(&cur, 0);
6242  for (int i = 0; i < nthreads; i++)
6243  {
6244  mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6245  mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6246  cur.cnt += threads[i].stats.cnt;
6247  cur.skipped += threads[i].stats.skipped;
6248  cur.retries += threads[i].stats.retries;
6249  cur.retried += threads[i].stats.retried;
6250  cur.serialization_failures +=
6251  threads[i].stats.serialization_failures;
6252  cur.deadlock_failures += threads[i].stats.deadlock_failures;
6253  }
6254 
6255  /* we count only actually executed transactions */
6256  cnt = cur.cnt - last->cnt;
6257  total_run = (now - test_start) / 1000000.0;
6258  tps = 1000000.0 * cnt / run;
6259  if (cnt > 0)
6260  {
6261  latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6262  sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6263  stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6264  lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6265  }
6266  else
6267  {
6268  latency = sqlat = stdev = lag = 0;
6269  }
6270  failures = getFailures(&cur) - getFailures(last);
6271  retried = cur.retried - last->retried;
6272 
6273  if (progress_timestamp)
6274  {
6275  snprintf(tbuf, sizeof(tbuf), "%.3f s",
6277  }
6278  else
6279  {
6280  /* round seconds are expected, but the thread may be late */
6281  snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6282  }
6283 
6284  fprintf(stderr,
6285  "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6286  tbuf, tps, latency, stdev, failures);
6287 
6288  if (throttle_delay)
6289  {
6290  fprintf(stderr, ", lag %.3f ms", lag);
6291  if (latency_limit)
6292  fprintf(stderr, ", " INT64_FORMAT " skipped",
6293  cur.skipped - last->skipped);
6294  }
6295 
6296  /* it can be non-zero only if max_tries is not equal to one */
6297  if (max_tries != 1)
6298  fprintf(stderr,
6299  ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6300  retried, cur.retries - last->retries);
6301  fprintf(stderr, "\n");
6302 
6303  *last = cur;
6304  *last_report = now;
struct cursor * cur
Definition: ecpg.c:28
static int64 getFailures(const StatsData *stats)
Definition: pgbench.c:4503

References StatsData::cnt, cur, StatsData::deadlock_failures, epoch_shift, fprintf, getFailures(), i, initStats(), INT64_FORMAT, StatsData::lag, StatsData::latency, latency_limit, max_tries, mergeSimpleStats(), now(), nthreads, PG_TIME_GET_DOUBLE, progress_timestamp, StatsData::retried, StatsData::retries, StatsData::serialization_failures, StatsData::skipped, snprintf, TState::stats, SimpleStats::sum, SimpleStats::sum2, and throttle_delay.

Referenced by threadRun().

◆ printResults()

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

Definition at line 6352 of file pgbench.c.

6358 {
6359  /* tps is about actually executed transactions during benchmarking */
6360  int64 failures = getFailures(total);
6361  int64 total_cnt = total->cnt + total->skipped + failures;
6362  double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
6363  double tps = total->cnt / bench_duration;
6364 
6365  /* Report test parameters. */
6366  printf("transaction type: %s\n",
6367  num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6368  printf("scaling factor: %d\n", scale);
6369  /* only print partitioning information if some partitioning was detected */
6370  if (partition_method != PART_NONE)
6371  printf("partition method: %s\npartitions: %d\n",
6373  printf("query mode: %s\n", QUERYMODE[querymode]);
6374  printf("number of clients: %d\n", nclients);
6375  printf("number of threads: %d\n", nthreads);
6376 
6377  if (max_tries)
6378  printf("maximum number of tries: %u\n", max_tries);
6379 
6380  if (duration <= 0)
6381  {
6382  printf("number of transactions per client: %d\n", nxacts);
6383  printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6384  total->cnt, nxacts * nclients);
6385  }
6386  else
6387  {
6388  printf("duration: %d s\n", duration);
6389  printf("number of transactions actually processed: " INT64_FORMAT "\n",
6390  total->cnt);
6391  }
6392 
6393  printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6394  failures, 100.0 * failures / total_cnt);
6395 
6396  if (failures_detailed)
6397  {
6398  printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6399  total->serialization_failures,
6400  100.0 * total->serialization_failures / total_cnt);
6401  printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6402  total->deadlock_failures,
6403  100.0 * total->deadlock_failures / total_cnt);
6404  }
6405 
6406  /* it can be non-zero only if max_tries is not equal to one */
6407  if (max_tries != 1)
6408  {
6409  printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6410  total->retried, 100.0 * total->retried / total_cnt);
6411  printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6412  }
6413 
6414  /* Remaining stats are nonsensical if we failed to execute any xacts */
6415  if (total->cnt + total->skipped <= 0)
6416  return;
6417 
6419  printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6420  total->skipped, 100.0 * total->skipped / total_cnt);
6421 
6422  if (latency_limit)
6423  printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6424  latency_limit / 1000.0, latency_late, total->cnt,
6425  (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6426 
6428  printSimpleStats("latency", &total->latency);
6429  else
6430  {
6431  /* no measurement, show average latency computed from run time */
6432  printf("latency average = %.3f ms%s\n",
6433  0.001 * total_duration * nclients / total_cnt,
6434  failures > 0 ? " (including failures)" : "");
6435  }
6436 
6437  if (throttle_delay)
6438  {
6439  /*
6440  * Report average transaction lag under rate limit throttling. This
6441  * is the delay between scheduled and actual start times for the
6442  * transaction. The measured lag may be caused by thread/client load,
6443  * the database load, or the Poisson throttling process.
6444  */
6445  printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
6446  0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6447  }
6448 
6449  /*
6450  * Under -C/--connect, each transaction incurs a significant connection
6451  * cost, it would not make much sense to ignore it in tps, and it would
6452  * not be tps anyway.
6453  *
6454  * Otherwise connections are made just once at the beginning of the run
6455  * and should not impact performance but for very short run, so they are
6456  * (right)fully ignored in tps.
6457  */
6458  if (is_connect)
6459  {
6460  printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
6461  printf("tps = %f (including reconnection times)\n", tps);
6462  }
6463  else
6464  {
6465  printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
6466  printf("tps = %f (without initial connection time)\n", tps);
6467  }
6468 
6469  /* Report per-script/command statistics */
6471  {
6472  int i;
6473 
6474  for (i = 0; i < num_scripts; i++)
6475  {
6476  if (per_script_stats)
6477  {
6478  StatsData *sstats = &sql_script[i].stats;
6479  int64 script_failures = getFailures(sstats);
6480  int64 script_total_cnt =
6481  sstats->cnt + sstats->skipped + script_failures;
6482 
6483  printf("SQL script %d: %s\n"
6484  " - weight: %d (targets %.1f%% of total)\n"
6485  " - " INT64_FORMAT " transactions (%.1f%% of total, tps = %f)\n",
6486  i + 1, sql_script[i].desc,
6487  sql_script[i].weight,
6488  100.0 * sql_script[i].weight / total_weight,
6489  sstats->cnt,
6490  100.0 * sstats->cnt / total->cnt,
6491  sstats->cnt / bench_duration);
6492 
6493  printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6494  script_failures,
6495  100.0 * script_failures / script_total_cnt);
6496 
6497  if (failures_detailed)
6498  {
6499  printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6500  sstats->serialization_failures,
6501  (100.0 * sstats->serialization_failures /
6502  script_total_cnt));
6503  printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6504  sstats->deadlock_failures,
6505  (100.0 * sstats->deadlock_failures /
6506  script_total_cnt));
6507  }
6508 
6509  /* it can be non-zero only if max_tries is not equal to one */
6510  if (max_tries != 1)
6511  {
6512  printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6513  sstats->retried,
6514  100.0 * sstats->retried / script_total_cnt);
6515  printf(" - total number of retries: " INT64_FORMAT "\n",
6516  sstats->retries);
6517  }
6518 
6519  if (throttle_delay && latency_limit && script_total_cnt > 0)
6520  printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6521  sstats->skipped,
6522  100.0 * sstats->skipped / script_total_cnt);
6523 
6524  printSimpleStats(" - latency", &sstats->latency);
6525  }
6526 
6527  /*
6528  * Report per-command statistics: latencies, retries after errors,
6529  * failures (errors without retrying).
6530  */
6531  if (report_per_command)
6532  {
6533  Command **commands;
6534 
6535  printf("%sstatement latencies in milliseconds%s:\n",
6536  per_script_stats ? " - " : "",
6537  (max_tries == 1 ?
6538  " and failures" :
6539  ", failures and retries"));
6540 
6541  for (commands = sql_script[i].commands;
6542  *commands != NULL;
6543  commands++)
6544  {
6545  SimpleStats *cstats = &(*commands)->stats;
6546 
6547  if (max_tries == 1)
6548  printf(" %11.3f %10" INT64_MODIFIER "d %s\n",
6549  (cstats->count > 0) ?
6550  1000.0 * cstats->sum / cstats->count : 0.0,
6551  (*commands)->failures,
6552  (*commands)->first_line);
6553  else
6554  printf(" %11.3f %10" INT64_MODIFIER "d %10" INT64_MODIFIER "d %s\n",
6555  (cstats->count > 0) ?
6556  1000.0 * cstats->sum / cstats->count : 0.0,
6557  (*commands)->failures,
6558  (*commands)->retries,
6559  (*commands)->first_line);
6560  }
6561  }
6562  }
6563  }
static void printSimpleStats(const char *prefix, SimpleStats *ss)
Definition: pgbench.c:6307
#define printf(...)
Definition: port.h:244
StatsData stats
Definition: pgbench.c:760

References StatsData::cnt, SimpleStats::count, StatsData::deadlock_failures, duration, failures_detailed, getFailures(), i, INT64_FORMAT, is_connect, StatsData::lag, StatsData::latency, latency_limit, SimpleStats::max, max_tries, nclients, nthreads, num_scripts, nxacts, PART_NONE, partition_method, PARTITION_METHOD, partitions, per_script_stats, PG_TIME_GET_DOUBLE, printf, printSimpleStats(), progress, querymode, QUERYMODE, report_per_command, StatsData::retried, StatsData::retries, scale, StatsData::serialization_failures, StatsData::skipped, sql_script, ParsedScript::stats, SimpleStats::sum, throttle_delay, and total_weight.

Referenced by main().

◆ printSimpleStats()

static void printSimpleStats ( const char *  prefix,
SimpleStats ss 
)
static

Definition at line 6307 of file pgbench.c.

6309 {
6310  if (ss->count > 0)
6311  {
6312  double latency = ss->sum / ss->count;
6313  double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6314 
6315  printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6316  printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6317  }

References SimpleStats::count, printf, SimpleStats::sum, and SimpleStats::sum2.

Referenced by printResults().

◆ printVerboseErrorMessages()

static void printVerboseErrorMessages ( CState st,
pg_time_usec_t now,
bool  is_retry 
)
static

Definition at line 3550 of file pgbench.c.

3552 {
3553  static PQExpBuffer buf = NULL;
3554 
3555  if (buf == NULL)
3556  buf = createPQExpBuffer();
3557  else
3559 
3560  printfPQExpBuffer(buf, "client %d ", st->id);
3561  appendPQExpBufferStr(buf, (is_retry ?
3562  "repeats the transaction after the error" :
3563  "ends the failed transaction"));
3564  appendPQExpBuffer(buf, " (try %u", st->tries);
3565 
3566  /* Print max_tries if it is not unlimited. */
3567  if (max_tries)
3568  appendPQExpBuffer(buf, "/%u", max_tries);
3569 
3570  /*
3571  * If the latency limit is used, print a percentage of the current
3572  * transaction latency from the latency limit.
3573  */
3574  if (latency_limit)
3575  {
3577  appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3578  (100.0 * (*now - st->txn_scheduled) / latency_limit));
3579  }
3580  appendPQExpBufferStr(buf, ")\n");
3581 
3582  pg_log_info("%s", buf->data);
PQExpBuffer createPQExpBuffer(void)
Definition: pqexpbuffer.c:72

References appendPQExpBuffer(), appendPQExpBufferStr(), buf, createPQExpBuffer(), CState::id, latency_limit, max_tries, now(), pg_log_info, pg_time_now_lazy(), printfPQExpBuffer(), resetPQExpBuffer(), CState::tries, and CState::txn_scheduled.

Referenced by advanceConnectionState().

◆ printVersion()

static void printVersion ( PGconn con)
static

Definition at line 6321 of file pgbench.c.

6323 {
6324  int server_ver = PQserverVersion(con);
6325  int client_ver = PG_VERSION_NUM;
6326 
6327  if (server_ver != client_ver)
6328  {
6329  const char *server_version;
6330  char sverbuf[32];
6331 
6332  /* Try to get full text form, might include "devel" etc */
6333  server_version = PQparameterStatus(con, "server_version");
6334  /* Otherwise fall back on server_ver */
6335  if (!server_version)
6336  {
6337  formatPGVersionNumber(server_ver, true,
6338  sverbuf, sizeof(sverbuf));
6339  server_version = sverbuf;
6340  }
6341 
6342  printf(_("%s (%s, server %s)\n"),
6343  "pgbench", PG_VERSION, server_version);
6344  }
6345  /* For version match, only print pgbench version */
6346  else
6347  printf("%s (%s)\n", "pgbench", PG_VERSION);
6348  fflush(stdout);
#define _(x)
Definition: elog.c:90
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7112
static void const char fflush(stdout)
static int server_version
Definition: pg_dumpall.c:110
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:177

References _, fflush(), formatPGVersionNumber(), PQparameterStatus(), PQserverVersion(), printf, server_version, and generate_unaccent_rules::stdout.

Referenced by main().

◆ process_backslash_command()

static Command* process_backslash_command ( PsqlScanState  sstate,
const char *  source 
)
static

Definition at line 5634 of file pgbench.c.

5636 {
5637  Command *my_command;
5638  PQExpBufferData word_buf;
5639  int word_offset;
5640  int offsets[MAX_ARGS]; /* offsets of argument words */
5641  int start_offset;
5642  int lineno;
5643  int j;
5644 
5645  initPQExpBuffer(&word_buf);
5646 
5647  /* Remember location of the backslash */
5648  start_offset = expr_scanner_offset(sstate) - 1;
5649  lineno = expr_scanner_get_lineno(sstate, start_offset);
5650 
5651  /* Collect first word of command */
5652  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5653  {
5654  termPQExpBuffer(&word_buf);
5655  return NULL;
5656  }
5657 
5658  /* Allocate and initialize Command structure */
5659  my_command = (Command *) pg_malloc0(sizeof(Command));
5660  my_command->type = META_COMMAND;
5661  my_command->argc = 0;
5662  initSimpleStats(&my_command->stats);
5663 
5664  /* Save first word (command name) */
5665  j = 0;
5666  offsets[j] = word_offset;
5667  my_command->argv[j++] = pg_strdup(word_buf.data);
5668  my_command->argc++;
5669 
5670  /* ... and convert it to enum form */
5671  my_command->meta = getMetaCommand(my_command->argv[0]);
5672 
5673  if (my_command->meta == META_SET ||
5674  my_command->meta == META_IF ||
5675  my_command->meta == META_ELIF)
5676  {
5678 
5679  /* For \set, collect var name */
5680  if (my_command->meta == META_SET)
5681  {
5682  if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5683  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5684  "missing argument", NULL, -1);
5685 
5686  offsets[j] = word_offset;
5687  my_command->argv[j++] = pg_strdup(word_buf.data);
5688  my_command->argc++;
5689  }
5690 
5691  /* then for all parse the expression */
5692  yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5693  my_command->argv[0]);
5694 
5695  if (expr_yyparse(yyscanner) != 0)
5696  {
5697  /* dead code: exit done from syntax_error called by yyerror */
5698  exit(1);
5699  }
5700 
5701  my_command->expr = expr_parse_result;
5702 
5703  /* Save line, trimming any trailing newline */
5704  my_command->first_line =
5706  start_offset,
5707  expr_scanner_offset(sstate),
5708  true);
5709 
5711 
5712  termPQExpBuffer(&word_buf);
5713 
5714  return my_command;
5715  }
5716 
5717  /* For all other commands, collect remaining words. */
5718  while (expr_lex_one_word(sstate, &word_buf, &word_offset))
5719  {
5720  /*
5721  * my_command->argv[0] is the command itself, so the max number of
5722  * arguments is one less than MAX_ARGS
5723  */
5724  if (j >= MAX_ARGS)
5725  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5726  "too many arguments", NULL, -1);
5727 
5728  offsets[j] = word_offset;
5729  my_command->argv[j++] = pg_strdup(word_buf.data);
5730  my_command->argc++;
5731  }
5732 
5733  /* Save line, trimming any trailing newline */
5734  my_command->first_line =
5736  start_offset,
5737  expr_scanner_offset(sstate),
5738  true);
5739 
5740  if (my_command->meta == META_SLEEP)
5741  {
5742  if (my_command->argc < 2)
5743  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5744  "missing argument", NULL, -1);
5745 
5746  if (my_command->argc > 3)
5747  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5748  "too many arguments", NULL,
5749  offsets[3] - start_offset);
5750 
5751  /*
5752  * Split argument into number and unit to allow "sleep 1ms" etc. We
5753  * don't have to terminate the number argument with null because it
5754  * will be parsed with atoi, which ignores trailing non-digit
5755  * characters.
5756  */
5757  if (my_command->argv[1][0] != ':')
5758  {
5759  char *c = my_command->argv[1];
5760  bool have_digit = false;
5761 
5762  /* Skip sign */
5763  if (*c == '+' || *c == '-')
5764  c++;
5765 
5766  /* Require at least one digit */
5767  if (*c && isdigit((unsigned char) *c))
5768  have_digit = true;
5769 
5770  /* Eat all digits */
5771  while (*c && isdigit((unsigned char) *c))
5772  c++;
5773 
5774  if (*c)
5775  {
5776  if (my_command->argc == 2 && have_digit)
5777  {
5778  my_command->argv[2] = c;
5779  offsets[2] = offsets[1] + (c - my_command->argv[1]);
5780  my_command->argc = 3;
5781  }
5782  else
5783  {
5784  /*
5785  * Raise an error if argument starts with non-digit
5786  * character (after sign).
5787  */
5788  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5789  "invalid sleep time, must be an integer",
5790  my_command->argv[1], offsets[1] - start_offset);
5791  }
5792  }
5793  }
5794 
5795  if (my_command->argc == 3)
5796  {
5797  if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
5798  pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
5799  pg_strcasecmp(my_command->argv[2], "s") != 0)
5800  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5801  "unrecognized time unit, must be us, ms or s",
5802  my_command->argv[2], offsets[2] - start_offset);
5803  }
5804  }
5805  else if (my_command->meta == META_SETSHELL)
5806  {
5807  if (my_command->argc < 3)
5808  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5809  "missing argument", NULL, -1);
5810  }
5811  else if (my_command->meta == META_SHELL)
5812  {
5813  if (my_command->argc < 2)
5814  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5815  "missing command", NULL, -1);
5816  }
5817  else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
5818  my_command->meta == META_STARTPIPELINE ||
5819  my_command->meta == META_ENDPIPELINE ||
5820  my_command->meta == META_SYNCPIPELINE)
5821  {
5822  if (my_command->argc != 1)
5823  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5824  "unexpected argument", NULL, -1);
5825  }
5826  else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
5827  {
5828  if (my_command->argc > 2)
5829  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5830  "too many arguments", NULL, -1);
5831  }
5832  else
5833  {
5834  /* my_command->meta == META_NONE */
5835  syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5836  "invalid command", NULL, -1);
5837  }
5838 
5839  termPQExpBuffer(&word_buf);
5840 
5841  return my_command;
static rewind_source * source
Definition: pg_rewind.c:89
static MetaCommand getMetaCommand(const char *cmd)
Definition: pgbench.c:2879
bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
int expr_yyparse(yyscan_t yyscanner)
PgBenchExpr * expr_parse_result
void expr_scanner_finish(yyscan_t yyscanner)
yyscan_t expr_scanner_init(PsqlScanState state, const char *source, int lineno, int start_offset, const char *command)
char * expr_scanner_get_substring(PsqlScanState state, int start_offset, int end_offset, bool chomp)
static core_yyscan_t yyscanner
Definition: pl_scanner.c:106
void * yyscan_t
Definition: psqlscan_int.h:60

References Command::argc, Command::argv, PQExpBufferData::data, exit(), Command::expr, expr_lex_one_word(), expr_parse_result, expr_scanner_finish(), expr_scanner_get_lineno(), expr_scanner_get_substring(), expr_scanner_init(), expr_scanner_offset(), expr_yyparse(), Command::first_line, getMetaCommand(), initPQExpBuffer(), initSimpleStats(), j, MAX_ARGS, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_ENDPIPELINE, META_GSET, META_IF, META_SET, META_SETSHELL, META_SHELL, META_SLEEP, META_STARTPIPELINE, META_SYNCPIPELINE, pg_malloc0(), pg_strcasecmp(), pg_strdup(), source, Command::stats, syntax_error(), termPQExpBuffer(), Command::type, and yyscanner.

Referenced by ParseScript().

◆ process_builtin()

static void process_builtin ( const BuiltinScript bi,
int  weight 
)
static

Definition at line 6100 of file pgbench.c.

6102 {
6103  ParseScript(bi->script, bi->desc, weight);
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:5904

References BuiltinScript::desc, ParseScript(), and BuiltinScript::script.

Referenced by main().

◆ process_file()

static void process_file ( const char *  filename,
int  weight 
)
static

Definition at line 6074 of file pgbench.c.

6076 {
6077  FILE *fd;
6078  char *buf;
6079 
6080  /* Slurp the file contents into "buf" */
6081  if (strcmp(filename, "-") == 0)
6082  fd = stdin;
6083  else if ((fd = fopen(filename, "r")) == NULL)
6084  pg_fatal("could not open file \"%s\": %m", filename);
6085 
6087 
6088  if (ferror(fd))
6089  pg_fatal("could not read file \"%s\": %m", filename);
6090 
6091  if (fd != stdin)
6092  fclose(fd);
6093 
6094  ParseScript(buf, filename, weight);
6095 
6096  free(buf);
static char * filename
Definition: pg_dumpall.c:119
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:6041

References buf, fd(), filename, free, ParseScript(), pg_fatal, and read_file_contents().

Referenced by main(), and process_psqlrc_file().

◆ processXactStats()

static void processXactStats ( TState thread,
CState st,
pg_time_usec_t now,
bool  skipped,
StatsData agg 
)
static

Definition at line 4665 of file pgbench.c.

4668 {
4669  double latency = 0.0,
4670  lag = 0.0;
4671  bool detailed = progress || throttle_delay || latency_limit ||
4673 
4674  if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4675  {
4677 
4678  /* compute latency & lag */
4679  latency = (*now) - st->txn_scheduled;
4680  lag = st->txn_begin - st->txn_scheduled;
4681  }
4682 
4683  /* keep detailed thread stats */
4684  accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4685 
4686  /* count transactions over the latency limit, if needed */
4687  if (latency_limit && latency > latency_limit)
4688  thread->latency_late++;
4689 
4690  /* client stat is just counting */
4691  st->cnt++;
4692 
4693  if (use_log)
4694  doLog(thread, st, agg, skipped, latency, lag);
4695 
4696  /* XXX could use a mutex here, but we choose not to */
4697  if (per_script_stats)
4698  accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4699  st->estatus, st->tries);
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:4545

References accumStats(), CState::cnt, doLog(), CState::estatus, ESTATUS_NO_ERROR, TState::latency_late, latency_limit, now(), per_script_stats, pg_time_now_lazy(), progress, sql_script, TState::stats, ParsedScript::stats, throttle_delay, CState::tries, CState::txn_begin, CState::txn_scheduled, CState::use_file, and use_log.

Referenced by advanceConnectionState().

◆ putVariable()

static bool putVariable ( Variables variables,
const char *  context,
char *  name,
const char *  value 
)
static

Definition at line 1828 of file pgbench.c.

1831 {
1832  Variable *var;
1833  char *val;
1834 
1835  var = lookupCreateVariable(variables, context, name);
1836  if (!var)
1837  return false;
1838 
1839  /* dup then free, in case value is pointing at this variable */
1840  val = pg_strdup(value);
1841 
1842  free(var->svalue);
1843  var->svalue = val;
1844  var->value.type = PGBT_NO_VALUE;
1845 
1846  return true;
static struct @155 value
static Variable * lookupCreateVariable(Variables *variables, const char *context, char *name)
Definition: pgbench.c:1791

References context, free, lookupCreateVariable(), name, pg_strdup(), PGBT_NO_VALUE, Variable::svalue, PgBenchValue::type, val, Variable::value, and value.

Referenced by main(), and readCommandResponse().

◆ putVariableInt()

static bool putVariableInt ( Variables variables,
const char *  context,
char *  name,
int64  value 
)
static

Definition at line 1870 of file pgbench.c.

1873 {
1874  PgBenchValue val;
1875 
1876  setIntValue(&val, value);
1877  return putVariableValue(variables, context, name, &val);

References context, name, putVariableValue(), setIntValue(), val, and value.

Referenced by main(), and runShellCommand().

◆ putVariableValue()

static bool putVariableValue ( Variables variables,
const char *  context,
char *  name,
const PgBenchValue value 
)
static

Definition at line 1851 of file pgbench.c.

1854 {
1855  Variable *var;
1856 
1857  var = lookupCreateVariable(variables, context, name);
1858  if (!var)
1859  return false;
1860 
1861  free(var->svalue);
1862  var->svalue = NULL;
1863  var->value = *value;
1864 
1865  return true;

References context, free, lookupCreateVariable(), name, Variable::svalue, Variable::value, and value.

Referenced by executeMetaCommand(), main(), and putVariableInt().

◆ read_file_contents()

static char* read_file_contents ( FILE *  fd)
static

Definition at line 6041 of file pgbench.c.

6043 {
6044  char *buf;
6045  size_t buflen = BUFSIZ;
6046  size_t used = 0;
6047 
6048  buf = (char *) pg_malloc(buflen);
6049 
6050  for (;;)
6051  {
6052  size_t nread;
6053 
6054  nread = fread(buf + used, 1, BUFSIZ, fd);
6055  used += nread;
6056  /* If fread() read less than requested, must be EOF or error */
6057  if (nread < BUFSIZ)
6058  break;
6059  /* Enlarge buf so we can read some more */
6060  buflen += BUFSIZ;
6061  buf = (char *) pg_realloc(buf, buflen);
6062  }
6063  /* There is surely room for a terminator */
6064  buf[used] = '\0';
6065 
6066  return buf;

References buf, fd(), pg_malloc(), and pg_realloc().

Referenced by process_file().

◆ readCommandResponse()

static bool readCommandResponse ( CState st,
MetaCommand  meta,
char *  varprefix 
)
static

Definition at line 3240 of file pgbench.c.

3242 {
3243  PGresult *res;
3244  PGresult *next_res;
3245  int qrynum = 0;
3246 
3247  /*
3248  * varprefix should be set only with \gset or \aset, and \endpipeline and
3249  * SQL commands do not need it.
3250  */
3251  Assert((meta == META_NONE && varprefix == NULL) ||
3252  ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3253  ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3254 
3255  res = PQgetResult(st->con);
3256 
3257  while (res != NULL)
3258  {
3259  bool is_last;
3260 
3261  /* peek at the next result to know whether the current is last */
3262  next_res = PQgetResult(st->con);
3263  is_last = (next_res == NULL);
3264 
3265  switch (PQresultStatus(res))
3266  {
3267  case PGRES_COMMAND_OK: /* non-SELECT commands */
3268  case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3269  if (is_last && meta == META_GSET)
3270  {
3271  pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3272  st->id, st->use_file, st->command, qrynum, 0);
3274  goto error;
3275  }
3276  break;
3277 
3278  case PGRES_TUPLES_OK:
3279  if ((is_last && meta == META_GSET) || meta == META_ASET)
3280  {
3281  int ntuples = PQntuples(res);
3282 
3283  if (meta == META_GSET && ntuples != 1)
3284  {
3285  /* under \gset, report the error */
3286  pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3287  st->id, st->use_file, st->command, qrynum, PQntuples(res));
3289  goto error;
3290  }
3291  else if (meta == META_ASET && ntuples <= 0)
3292  {
3293  /* coldly skip empty result under \aset */
3294  break;
3295  }
3296 
3297  /* store results into variables */
3298  for (int fld = 0; fld < PQnfields(res); fld++)
3299  {
3300  char *varname = PQfname(res, fld);
3301 
3302  /* allocate varname only if necessary, freed below */
3303  if (*varprefix != '\0')
3304  varname = psprintf("%s%s", varprefix, varname);
3305 
3306  /* store last row result as a string */
3307  if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3308  PQgetvalue(res, ntuples - 1, fld)))
3309  {
3310  /* internal error */
3311  pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3312  st->id, st->use_file, st->command, qrynum, varname);
3314  goto error;
3315  }
3316 
3317  if (*varprefix != '\0')
3318  pg_free(varname);
3319  }
3320  }
3321  /* otherwise the result is simply thrown away by PQclear below */
3322  break;
3323 
3324  case PGRES_PIPELINE_SYNC:
3325  pg_log_debug("client %d pipeline ending, ongoing syncs: %d",
3326  st->id, st->num_syncs);
3327  st->num_syncs--;
3328  if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
3329  pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3330  PQerrorMessage(st->con));
3331  break;
3332 
3333  case PGRES_NONFATAL_ERROR:
3334  case PGRES_FATAL_ERROR:
3336  PG_DIAG_SQLSTATE));
3337  if (canRetryError(st->estatus))
3338  {
3339  if (verbose_errors)
3340  commandError(st, PQerrorMessage(st->con));
3341  goto error;
3342  }
3343  /* fall through */
3344 
3345  default:
3346  /* anything else is unexpected */
3347  pg_log_error("client %d script %d aborted in command %d query %d: %s",
3348  st->id, st->use_file, st->command, qrynum,
3349  PQerrorMessage(st->con));
3350  goto error;
3351  }
3352 
3353  PQclear(res);
3354  qrynum++;
3355  res = next_res;
3356  }
3357 
3358  if (qrynum == 0)
3359  {
3360  pg_log_error("client %d command %d: no results", st->id, st->command);
3361  return false;
3362  }
3363 
3364  return true;
3365 
3366 error:
3367  PQclear(res);
3368  PQclear(next_res);
3369  do
3370  {
3371  res = PQgetResult(st->con);
3372  PQclear(res);
3373  } while (res);
3374 
3375  return false;
char * PQfname(const PGresult *res, int field_num)
Definition: fe-exec.c:3567
int PQnfields(const PGresult *res)
Definition: fe-exec.c:3489
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:111
@ PGRES_EMPTY_QUERY
Definition: libpq-fe.h:99
@ PGRES_NONFATAL_ERROR
Definition: libpq-fe.h:110
static EStatus getSQLErrorStatus(const char *sqlState)
Definition: pgbench.c:3207
static void commandError(CState *st, const char *message)
Definition: pgbench.c:3037
static void error(void)
Definition: sql-dyntest.c:147

References Assert, canRetryError(), CState::command, commandError(), CState::con, error(), CState::estatus, ESTATUS_META_COMMAND_ERROR, getSQLErrorStatus(), CState::id, META_ASET, META_ENDPIPELINE, META_GSET, META_NONE, CState::num_syncs, PG_DIAG_SQLSTATE, pg_free(), pg_log_debug, pg_log_error, PGRES_COMMAND_OK, PGRES_EMPTY_QUERY, PGRES_FATAL_ERROR, PGRES_NONFATAL_ERROR, PGRES_PIPELINE_SYNC, PGRES_TUPLES_OK, PQclear(), PQerrorMessage(), PQexitPipelineMode(), PQfname(), PQgetResult(), PQgetvalue(), PQnfields(), PQntuples(), PQresultErrorField(), PQresultStatus(), psprintf(), putVariable(), res, CState::use_file, CState::variables, and verbose_errors.

Referenced by advanceConnectionState().

◆ replaceVariable()

static char* replaceVariable ( char **  sql,
char *  param,
int  len,
char *  value 
)
static

Definition at line 1915 of file pgbench.c.

1917 {
1918  int valueln = strlen(value);
1919 
1920  if (valueln > len)
1921  {
1922  size_t offset = param - *sql;
1923 
1924  *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1925  param = *sql + offset;
1926  }
1927 
1928  if (valueln != len)
1929  memmove(param + valueln, param + len, strlen(param + len) + 1);
1930  memcpy(param, value, valueln);
1931 
1932  return param + valueln;

References len, pg_realloc(), and value.

Referenced by assignVariables(), and parseQuery().

◆ runInitSteps()

static void runInitSteps ( const char *  initialize_steps)
static

Definition at line 5222 of file pgbench.c.

5224 {
5225  PQExpBufferData stats;
5226  PGconn *con;
5227  const char *step;
5228  double run_time = 0.0;
5229  bool first = true;
5230 
5231  initPQExpBuffer(&stats);
5232 
5233  if ((con = doConnect()) == NULL)
5234  pg_fatal("could not create connection for initialization");
5235 
5236  setup_cancel_handler(NULL);
5237  SetCancelConn(con);
5238 
5239  for (step = initialize_steps; *step != '\0'; step++)
5240  {
5241  char *op = NULL;
5243 
5244  switch (*step)
5245  {
5246  case 'd':
5247  op = "drop tables";
5248  initDropTables(con);
5249  break;
5250  case 't':
5251  op = "create tables";
5252  initCreateTables(con);
5253  break;
5254  case 'g':
5255  op = "client-side generate";
5257  break;
5258  case 'G':
5259  op = "server-side generate";
5261  break;
5262  case 'v':
5263  op = "vacuum";
5264  initVacuum(con);
5265  break;
5266  case 'p':
5267  op = "primary keys";
5268  initCreatePKeys(con);
5269  break;
5270  case 'f':
5271  op = "foreign keys";
5272  initCreateFKeys(con);
5273  break;
5274  case ' ':
5275  break; /* ignore */
5276  default:
5277  pg_log_error("unrecognized initialization step \"%c\"", *step);
5278  PQfinish(con);
5279  exit(1);
5280  }
5281 
5282  if (op != NULL)
5283  {
5284  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5285 
5286  if (!first)
5287  appendPQExpBufferStr(&stats, ", ");
5288  else
5289  first = false;
5290 
5291  appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5292 
5293  run_time += elapsed_sec;
5294  }
5295  }
5296 
5297  fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5298  ResetCancelConn();
5299  PQfinish(con);
5300  termPQExpBuffer(&stats);
void ResetCancelConn(void)
Definition: cancel.c:107
void SetCancelConn(PGconn *conn)
Definition: cancel.c:77
void setup_cancel_handler(void(*query_cancel_callback)(void))
Definition: cancel.c:183
static void initCreatePKeys(PGconn *con)
Definition: pgbench.c:5138
static void initDropTables(PGconn *con)
Definition: pgbench.c:4716
static void initGenerateDataServerSide(PGconn *con)
Definition: pgbench.c:5080
static void initCreateFKeys(PGconn *con)
Definition: pgbench.c:5176
static void initVacuum(PGconn *con)
Definition: pgbench.c:5125
static void initCreateTables(PGconn *con)
Definition: pgbench.c:4807
static void initGenerateDataClientSide(PGconn *con)
Definition: pgbench.c:5048

References appendPQExpBuffer(), appendPQExpBufferStr(), PQExpBufferData::data, doConnect(), exit(), fprintf, initCreateFKeys(), initCreatePKeys(), initCreateTables(), initDropTables(), initGenerateDataClientSide(), initGenerateDataServerSide(), initPQExpBuffer(), initVacuum(), pg_fatal, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), PQfinish(), ResetCancelConn(), SetCancelConn(), setup_cancel_handler(), start, and termPQExpBuffer().

Referenced by main().

◆ runShellCommand()

static bool runShellCommand ( Variables variables,
char *  variable,
char **  argv,
int  argc 
)
static

Definition at line 2921 of file pgbench.c.

2923 {
2924  char command[SHELL_COMMAND_SIZE];
2925  int i,
2926  len = 0;
2927  FILE *fp;
2928  char res[64];
2929  char *endptr;
2930  int retval;
2931 
2932  /*----------
2933  * Join arguments with whitespace separators. Arguments starting with
2934  * exactly one colon are treated as variables:
2935  * name - append a string "name"
2936  * :var - append a variable named 'var'
2937  * ::name - append a string ":name"
2938  *----------
2939  */
2940  for (i = 0; i < argc; i++)
2941  {
2942  char *arg;
2943  int arglen;
2944 
2945  if (argv[i][0] != ':')
2946  {
2947  arg = argv[i]; /* a string literal */
2948  }
2949  else if (argv[i][1] == ':')
2950  {
2951  arg = argv[i] + 1; /* a string literal starting with colons */
2952  }
2953  else if ((arg = getVariable(variables, argv[i] + 1)) == NULL)
2954  {
2955  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[i]);
2956  return false;
2957  }
2958 
2959  arglen = strlen(arg);
2960  if (len + arglen + (i > 0 ? 1 : 0) >= SHELL_COMMAND_SIZE - 1)
2961  {
2962  pg_log_error("%s: shell command is too long", argv[0]);
2963  return false;
2964  }
2965 
2966  if (i > 0)
2967  command[len++] = ' ';
2968  memcpy(command + len, arg, arglen);
2969  len += arglen;
2970  }
2971 
2972  command[len] = '\0';
2973 
2974  fflush(NULL); /* needed before either system() or popen() */
2975 
2976  /* Fast path for non-assignment case */
2977  if (variable == NULL)
2978  {
2979  if (system(command))
2980  {
2981  if (!timer_exceeded)
2982  pg_log_error("%s: could not launch shell command", argv[0]);
2983  return false;
2984  }
2985  return true;
2986  }
2987 
2988  /* Execute the command with pipe and read the standard output. */
2989  if ((fp = popen(command, "r")) == NULL)
2990  {
2991  pg_log_error("%s: could not launch shell command", argv[0]);
2992  return false;
2993  }
2994  if (fgets(res, sizeof(res), fp) == NULL)
2995  {
2996  if (!timer_exceeded)
2997  pg_log_error("%s: could not read result of shell command", argv[0]);
2998  (void) pclose(fp);
2999  return false;
3000  }
3001  if (pclose(fp) < 0)
3002  {
3003  pg_log_error("%s: could not run shell command: %m", argv[0]);
3004  return false;
3005  }
3006 
3007  /* Check whether the result is an integer and assign it to the variable */
3008  retval = (int) strtol(res, &endptr, 10);
3009  while (*endptr != '\0' && isspace((unsigned char) *endptr))
3010  endptr++;
3011  if (*res == '\0' || *endptr != '\0')
3012  {
3013  pg_log_error("%s: shell command must return an integer (not \"%s\")", argv[0], res);
3014  return false;
3015  }
3016  if (!putVariableInt(variables, "setshell", variable, retval))
3017  return false;
3018 
3019  pg_log_debug("%s: shell parameter name: \"%s\", value: \"%s\"", argv[0], argv[1], res);
3020 
3021  return true;
void * arg
#define SHELL_COMMAND_SIZE
Definition: pgbench.c:347

References arg, fflush(), getVariable(), i, len, pg_log_debug, pg_log_error, putVariableInt(), res, SHELL_COMMAND_SIZE, and timer_exceeded.

Referenced by executeMetaCommand().

◆ sendCommand()

static bool sendCommand ( CState st,
Command command 
)
static

Definition at line 3154 of file pgbench.c.

3156 {
3157  int r;
3158 
3159  if (querymode == QUERY_SIMPLE)
3160  {
3161  char *sql;
3162 
3163  sql = pg_strdup(command->argv[0]);
3164  sql = assignVariables(&st->variables, sql);
3165 
3166  pg_log_debug("client %d sending %s", st->id, sql);
3167  r = PQsendQuery(st->con, sql);
3168  free(sql);
3169  }
3170  else if (querymode == QUERY_EXTENDED)
3171  {
3172  const char *sql = command->argv[0];
3173  const char *params[MAX_ARGS];
3174 
3175  getQueryParams(&st->variables, command, params);
3176 
3177  pg_log_debug("client %d sending %s", st->id, sql);
3178  r = PQsendQueryParams(st->con, sql, command->argc - 1,
3179  NULL, params, NULL, NULL, 0);
3180  }
3181  else if (querymode == QUERY_PREPARED)
3182  {
3183  const char *params[MAX_ARGS];
3184 
3185  prepareCommand(st, st->command);
3186  getQueryParams(&st->variables, command, params);
3187 
3188  pg_log_debug("client %d sending %s", st->id, command->prepname);
3189  r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3190  params, NULL, NULL, 0);
3191  }
3192  else /* unknown sql mode */
3193  r = 0;
3194 
3195  if (r == 0)
3196  {
3197  pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3198  return false;
3199  }
3200  else
3201  return true;
int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1492
int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char *const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat)
Definition: fe-exec.c:1633
static char * assignVariables(Variables *variables, char *sql)
Definition: pgbench.c:1935
static void getQueryParams(Variables *variables, const Command *command, const char **params)
Definition: pgbench.c:1971

References Command::argc, Command::argv, assignVariables(), CState::command, CState::con, free, getQueryParams(), CState::id, MAX_ARGS, pg_log_debug, pg_strdup(), PQsendQuery(), PQsendQueryParams(), PQsendQueryPrepared(), prepareCommand(), Command::prepname, QUERY_EXTENDED, QUERY_PREPARED, QUERY_SIMPLE, querymode, and CState::variables.

Referenced by advanceConnectionState().

◆ set_random_seed()

static bool set_random_seed ( const char *  seed)
static

Definition at line 6570 of file pgbench.c.

6572 {
6573  uint64 iseed;
6574 
6575  if (seed == NULL || strcmp(seed, "time") == 0)
6576  {
6577  /* rely on current time */
6578  iseed = pg_time_now();
6579  }
6580  else if (strcmp(seed, "rand") == 0)
6581  {
6582  /* use some "strong" random source */
6583  if (!pg_strong_random(&iseed, sizeof(iseed)))
6584  {
6585  pg_log_error("could not generate random seed");
6586  return false;
6587  }
6588  }
6589  else
6590  {
6591  /* parse unsigned-int seed value */
6592  unsigned long ulseed;
6593  char garbage;
6594 
6595  /* Don't try to use UINT64_FORMAT here; it might not work for sscanf */
6596  if (sscanf(seed, "%lu%c", &ulseed, &garbage) != 1)
6597  {
6598  pg_log_error("unrecognized random seed option \"%s\"", seed);
6599  pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6600  return false;
6601  }
6602  iseed = (uint64) ulseed;
6603  }
6604 
6605  if (seed != NULL)
6606  pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
6607 
6608  random_seed = iseed;
6609 
6610  /* Initialize base_random_sequence using seed */
6611  pg_prng_seed(&base_random_sequence, (uint64) iseed);
6612 
6613  return true;
bool pg_strong_random(void *buf, size_t len)

References base_random_sequence, pg_log_error, pg_log_error_detail, pg_log_info, pg_prng_seed(), pg_strong_random(), pg_time_now(), and random_seed.

Referenced by main().

◆ setalarm()

static void setalarm ( int  seconds)
static

Definition at line 7716 of file pgbench.c.

7718 {
7720  alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7710
pqsigfunc pqsignal(int signo, pqsigfunc func)
#define SIGALRM
Definition: win32_port.h:174

References handle_sig_alarm(), pqsignal(), and SIGALRM.

Referenced by main().

◆ setBoolValue()

static void setBoolValue ( PgBenchValue pv,
bool  bval 
)
static

Definition at line 2101 of file pgbench.c.

2103 {
2104  pv->type = PGBT_BOOLEAN;
2105  pv->u.bval = bval;

References PgBenchValue::bval, PGBT_BOOLEAN, PgBenchValue::type, and PgBenchValue::u.

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

◆ setDoubleValue()

static void setDoubleValue ( PgBenchValue pv,
double  dval 
)
static

Definition at line 2117 of file pgbench.c.

2119 {
2120  pv->type = PGBT_DOUBLE;
2121  pv->u.dval = dval;

References PgBenchValue::dval, PGBT_DOUBLE, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalStandardFunc(), and makeVariableValue().

◆ setIntValue()

static void setIntValue ( PgBenchValue pv,
int64  ival 
)
static

Definition at line 2109 of file pgbench.c.

2111 {
2112  pv->type = PGBT_INT;
2113  pv->u.ival = ival;

References PgBenchValue::ival, PGBT_INT, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalStandardFunc(), makeVariableValue(), and putVariableInt().

◆ setNullValue()

static void setNullValue ( PgBenchValue pv)
static

Definition at line 2093 of file pgbench.c.

2095 {
2096  pv->type = PGBT_NULL;
2097  pv->u.ival = 0;

References PgBenchValue::ival, PGBT_NULL, PgBenchValue::type, and PgBenchValue::u.

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

◆ skip_sql_comments()

static char* skip_sql_comments ( char *  sql_command)
static

Definition at line 5513 of file pgbench.c.

5515 {
5516  char *p = sql_command;
5517 
5518  /* Skip any leading whitespace, as well as "--" style comments */
5519  for (;;)
5520  {
5521  if (isspace((unsigned char) *p))
5522  p++;
5523  else if (strncmp(p, "--", 2) == 0)
5524  {
5525  p = strchr(p, '\n');
5526  if (p == NULL)
5527  return NULL;
5528  p++;
5529  }
5530  else
5531  break;
5532  }
5533 
5534  /* NULL if there's nothing but whitespace and comments */
5535  if (*p == '\0')
5536  return NULL;
5537 
5538  return p;

Referenced by create_sql_command().

◆ socket_has_input()

static bool socket_has_input ( socket_set sa,
int  fd,
int  idx 
)
static

Definition at line 7920 of file pgbench.c.

7922 {
7923  return (FD_ISSET(fd, &sa->fds) != 0);

References fd().

Referenced by threadRun().

◆ strtodouble()

bool strtodouble ( const char *  str,
bool  errorOK,
double *  dv 
)

Definition at line 1058 of file pgbench.c.

1060 {
1061  char *end;
1062 
1063  errno = 0;
1064  *dv = strtod(str, &end);
1065 
1066  if (unlikely(errno != 0))
1067  {
1068  if (!errorOK)
1069  pg_log_error("value \"%s\" is out of range for type double", str);
1070  return false;
1071  }
1072 
1073  if (unlikely(end == str || *end != '\0'))
1074  {
1075  if (!errorOK)
1076  pg_log_error("invalid input syntax for type double: \"%s\"", str);
1077  return false;
1078  }
1079  return true;

References pg_log_error, str, and unlikely.

Referenced by makeVariableValue().

◆ strtoint64()

bool strtoint64 ( const char *  str,
bool  errorOK,
int64 *  result 
)

Definition at line 987 of file pgbench.c.

989 {
990  const char *ptr = str;
991  int64 tmp = 0;
992  bool neg = false;
993 
994  /*
995  * Do our own scan, rather than relying on sscanf which might be broken
996  * for long long.
997  *
998  * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
999  * value as a negative number.
1000  */
1001 
1002  /* skip leading spaces */
1003  while (*ptr && isspace((unsigned char) *ptr))
1004  ptr++;
1005 
1006  /* handle sign */
1007  if (*ptr == '-')
1008  {
1009  ptr++;
1010  neg = true;
1011  }
1012  else if (*ptr == '+')
1013  ptr++;
1014 
1015  /* require at least one digit */
1016  if (unlikely(!isdigit((unsigned char) *ptr)))
1017  goto invalid_syntax;
1018 
1019  /* process digits */
1020  while (*ptr && isdigit((unsigned char) *ptr))
1021  {
1022  int8 digit = (*ptr++ - '0');
1023 
1024  if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
1025  unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
1026  goto out_of_range;
1027  }
1028 
1029  /* allow trailing whitespace, but not other trailing chars */
1030  while (*ptr != '\0' && isspace((unsigned char) *ptr))
1031  ptr++;
1032 
1033  if (unlikely(*ptr != '\0'))
1034  goto invalid_syntax;
1035 
1036  if (!neg)
1037  {
1038  if (unlikely(tmp == PG_INT64_MIN))
1039  goto out_of_range;
1040  tmp = -tmp;
1041  }
1042 
1043  *result = tmp;
1044  return true;
1045 
1046 out_of_range:
1047  if (!errorOK)
1048  pg_log_error("value \"%s\" is out of range for type bigint", str);
1049  return false;
1050 
1051 invalid_syntax:
1052  if (!errorOK)
1053  pg_log_error("invalid input syntax for type bigint: \"%s\"", str);
1054  return false;
signed char int8
Definition: c.h:492

References PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), str, and unlikely.

Referenced by makeVariableValue().

◆ syntax_error()

void syntax_error ( const char *  source,
int  lineno,
const char *  line,
const char *  command,
const char *  msg,
const char *  more,
int  column 
)

Definition at line 5477 of file pgbench.c.

5481 {
5483 
5484  initPQExpBuffer(&buf);
5485 
5486  printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5487  if (more != NULL)
5488  appendPQExpBuffer(&buf, " (%s)", more);
5489  if (column >= 0 && line == NULL)
5490  appendPQExpBuffer(&buf, " at column %d", column + 1);
5491  if (command != NULL)
5492  appendPQExpBuffer(&buf, " in command \"%s\"", command);
5493 
5494  pg_log_error("%s", buf.data);
5495 
5496  termPQExpBuffer(&buf);
5497 
5498  if (line != NULL)
5499  {
5500  fprintf(stderr, "%s\n", line);
5501  if (column >= 0)
5502  fprintf(stderr, "%*c error found here\n", column + 1, '^');
5503  }
5504 
5505  exit(1);

References appendPQExpBuffer(), buf, exit(), fprintf, initPQExpBuffer(), pg_log_error, printfPQExpBuffer(), source, and termPQExpBuffer().

Referenced by ParseScript(), process_backslash_command(), and string_to_uuid().

◆ threadRun()

static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun ( void *  arg)
static

Definition at line 7394 of file pgbench.c.

7396 {
7397  TState *thread = (TState *) arg;
7398  CState *state = thread->state;
7400  int nstate = thread->nstate;
7401  int remains = nstate; /* number of remaining clients */
7402  socket_set *sockets = alloc_socket_set(nstate);
7403  int64 thread_start,
7404  last_report,
7405  next_report;
7406  StatsData last,
7407  aggs;
7408 
7409  /* open log file if requested */
7410  if (use_log)
7411  {
7412  char logpath[MAXPGPATH];
7413  char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7414 
7415  if (thread->tid == 0)
7416  snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7417  else
7418  snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7419 
7420  thread->logfile = fopen(logpath, "w");
7421 
7422  if (thread->logfile == NULL)
7423  pg_fatal("could not open logfile \"%s\": %m", logpath);
7424  }
7425 
7426  /* explicitly initialize the state machines */
7427  for (int i = 0; i < nstate; i++)
7429 
7430  /* READY */
7432 
7433  thread_start = pg_time_now();
7434  thread->started_time = thread_start;
7435  thread->conn_duration = 0;
7436  last_report = thread_start;
7437  next_report = last_report + (int64) 1000000 * progress;
7438 
7439  /* STEADY */
7440  if (!is_connect)
7441  {
7442  /* make connections to the database before starting */
7443  for (int i = 0; i < nstate; i++)
7444  {
7445  if ((state[i].con = doConnect()) == NULL)
7446  {
7447  /* coldly abort on initial connection failure */
7448  pg_fatal("could not create connection for client %d",
7449  state[i].id);
7450  }
7451  }
7452  }
7453 
7454  /* GO */
7456 
7457  start = pg_time_now();
7458  thread->bench_start = start;
7459  thread->throttle_trigger = start;
7460 
7461  /*
7462  * The log format currently has Unix epoch timestamps with whole numbers
7463  * of seconds. Round the first aggregate's start time down to the nearest
7464  * Unix epoch second (the very first aggregate might really have started a
7465  * fraction of a second later, but later aggregates are measured from the
7466  * whole number time that is actually logged).
7467  */
7468  initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
7469  last = aggs;
7470 
7471  /* loop till all clients have terminated */
7472  while (remains > 0)
7473  {
7474  int nsocks; /* number of sockets to be waited for */
7475  pg_time_usec_t min_usec;
7476  pg_time_usec_t now = 0; /* set this only if needed */
7477 
7478  /*
7479  * identify which client sockets should be checked for input, and
7480  * compute the nearest time (if any) at which we need to wake up.
7481  */
7482  clear_socket_set(sockets);
7483  nsocks = 0;
7484  min_usec = PG_INT64_MAX;
7485  for (int i = 0; i < nstate; i++)
7486  {
7487  CState *st = &state[i];
7488 
7489  if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
7490  {
7491  /* a nap from the script, or under throttling */
7492  pg_time_usec_t this_usec;
7493 
7494  /* get current time if needed */
7496 
7497  /* min_usec should be the minimum delay across all clients */
7498  this_usec = (st->state == CSTATE_SLEEP ?
7499  st->sleep_until : st->txn_scheduled) - now;
7500  if (min_usec > this_usec)
7501  min_usec = this_usec;
7502  }
7503  else if (st->state == CSTATE_WAIT_RESULT ||
7505  {
7506  /*
7507  * waiting for result from server - nothing to do unless the
7508  * socket is readable
7509  */
7510  int sock = PQsocket(st->con);
7511 
7512  if (sock < 0)
7513  {
7514  pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7515  goto done;
7516  }
7517 
7518  add_socket_to_set(sockets, sock, nsocks++);
7519  }
7520  else if (st->state != CSTATE_ABORTED &&
7521  st->state != CSTATE_FINISHED)
7522  {
7523  /*
7524  * This client thread is ready to do something, so we don't
7525  * want to wait. No need to examine additional clients.
7526  */
7527  min_usec = 0;
7528  break;
7529  }
7530  }
7531 
7532  /* also wake up to print the next progress report on time */
7533  if (progress && min_usec > 0 && thread->tid == 0)
7534  {
7536 
7537  if (now >= next_report)
7538  min_usec = 0;
7539  else if ((next_report - now) < min_usec)
7540  min_usec = next_report - now;
7541  }
7542 
7543  /*
7544  * If no clients are ready to execute actions, sleep until we receive
7545  * data on some client socket or the timeout (if any) elapses.
7546  */
7547  if (min_usec > 0)
7548  {
7549  int rc = 0;
7550 
7551  if (min_usec != PG_INT64_MAX)
7552  {
7553  if (nsocks > 0)
7554  {
7555  rc = wait_on_socket_set(sockets, min_usec);
7556  }
7557  else /* nothing active, simple sleep */
7558  {
7559  pg_usleep(min_usec);
7560  }
7561  }
7562  else /* no explicit delay, wait without timeout */
7563  {
7564  rc = wait_on_socket_set(sockets, 0);
7565  }
7566 
7567  if (rc < 0)
7568  {
7569  if (errno == EINTR)
7570  {
7571  /* On EINTR, go back to top of loop */
7572  continue;
7573  }
7574  /* must be something wrong */
7575  pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
7576  goto done;
7577  }
7578  }
7579  else
7580  {
7581  /* min_usec <= 0, i.e. something needs to be executed now */
7582 
7583  /* If we didn't wait, don't try to read any data */
7584  clear_socket_set(sockets);
7585  }
7586 
7587  /* ok, advance the state machine of each connection */
7588  nsocks = 0;
7589  for (int i = 0; i < nstate; i++)
7590  {
7591  CState *st = &state[i];
7592 
7593  if (st->state == CSTATE_WAIT_RESULT ||
7595  {
7596  /* don't call advanceConnectionState unless data is available */
7597  int sock = PQsocket(st->con);
7598 
7599  if (sock < 0)
7600  {
7601  pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7602  goto done;
7603  }
7604 
7605  if (!socket_has_input(sockets, sock, nsocks++))
7606  continue;
7607  }
7608  else if (st->state == CSTATE_FINISHED ||
7609  st->state == CSTATE_ABORTED)
7610  {
7611  /* this client is done, no need to consider it anymore */
7612  continue;
7613  }
7614 
7615  advanceConnectionState(thread, st, &aggs);
7616 
7617  /*
7618  * If --exit-on-abort is used, the program is going to exit when
7619  * any client is aborted.
7620  */
7621  if (exit_on_abort && st->state == CSTATE_ABORTED)
7622  goto done;
7623 
7624  /*
7625  * If advanceConnectionState changed client to finished state,
7626  * that's one fewer client that remains.
7627  */
7628  else if (st->state == CSTATE_FINISHED ||
7629  st->state == CSTATE_ABORTED)
7630  remains--;
7631  }
7632 
7633  /* progress report is made by thread 0 for all threads */
7634  if (progress && thread->tid == 0)
7635  {
7636  pg_time_usec_t now2 = pg_time_now();
7637 
7638  if (now2 >= next_report)
7639  {
7640  /*
7641  * Horrible hack: this relies on the thread pointer we are
7642  * passed to be equivalent to threads[0], that is the first
7643  * entry of the threads array. That is why this MUST be done
7644  * by thread 0 and not any other.
7645  */
7646  printProgressReport(thread, thread_start, now2,
7647  &last, &last_report);
7648 
7649  /*
7650  * Ensure that the next report is in the future, in case
7651  * pgbench/postgres got stuck somewhere.
7652  */
7653  do
7654  {
7655  next_report += (int64) 1000000 * progress;
7656  } while (now2 >= next_report);
7657  }
7658  }
7659  }
7660 
7661 done:
7662  if (exit_on_abort)
7663  {
7664  /*
7665  * Abort if any client is not finished, meaning some error occurred.
7666  */
7667  for (int i = 0; i < nstate; i++)
7668  {
7669  if (state[i].state != CSTATE_FINISHED)
7670  {
7671  pg_log_error("Run was aborted due to an error in thread %d",
7672  thread->tid);
7673  exit(2);
7674  }
7675  }
7676  }
7677 
7678  disconnect_all(state, nstate);
7679 
7680  if (thread->logfile)
7681  {
7682  if (agg_interval > 0)
7683  {
7684  /* log aggregated but not yet reported transactions */
7685  doLog(thread, state, &aggs, false, 0, 0);
7686  }
7687  fclose(thread->logfile);
7688  thread->logfile = NULL;
7689  }
7690  free_socket_set(sockets);
#define PG_INT64_MAX
Definition: c.h:592
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7173
#define MAXPGPATH
#define THREAD_BARRIER_WAIT(barrier)
Definition: pgbench.c:154
#define SOCKET_WAIT_METHOD
Definition: pgbench.c:106
static void free_socket_set(socket_set *sa)
Definition: pgbench.c:7865
static void clear_socket_set(socket_set *sa)
Definition: pgbench.c:7871
static void add_socket_to_set(socket_set *sa, int fd, int idx)
Definition: pgbench.c:7878
#define THREAD_FUNC_RETURN
Definition: pgbench.c:145
static void advanceConnectionState(TState *thread, CState *st, StatsData *agg)
Definition: pgbench.c:3588
static void printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
Definition: pgbench.c:6213
static bool socket_has_input(socket_set *sa, int fd, int idx)
Definition: pgbench.c:7920
static int wait_on_socket_set(socket_set *sa, int64 usecs)
Definition: pgbench.c:7903
static socket_set * alloc_socket_set(int count)
Definition: pgbench.c:7859
void pg_usleep(long microsec)
Definition: signal.c:53
pg_time_usec_t started_time
Definition: pgbench.c:665
#define EINTR
Definition: win32_port.h:374

References add_socket_to_set(), advanceConnectionState(), agg_interval, alloc_socket_set(), arg, barrier, TState::bench_start, clear_socket_set(), CState::con, TState::conn_duration, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_FINISHED, CSTATE_SLEEP, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, disconnect_all(), doConnect(), doLog(), EINTR, epoch_shift, exit(), exit_on_abort, free_socket_set(), i, initStats(), is_connect, TState::logfile, logfile_prefix, main_pid, MAXPGPATH, now(), TState::nstate, pg_fatal, PG_INT64_MAX, pg_log_error, pg_time_now(), pg_time_now_lazy(), pg_usleep(), PQerrorMessage(), PQsocket(), printProgressReport(), progress, CState::sleep_until, snprintf, socket_has_input(), SOCKET_WAIT_METHOD, start, TState::started_time, CState::state, TState::state, THREAD_BARRIER_WAIT, THREAD_FUNC_RETURN, TState::throttle_trigger, TState::tid, CState::txn_scheduled, use_log, and wait_on_socket_set().

Referenced by main().

◆ tryExecuteStatement()

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

Definition at line 1515 of file pgbench.c.

1517 {
1518  PGresult *res;
1519 
1520  res = PQexec(con, sql);
1522  {
1523  pg_log_error("%s", PQerrorMessage(con));
1524  pg_log_error_detail("(ignoring this error and continuing anyway)");
1525  }
1526  PQclear(res);

References pg_log_error, pg_log_error_detail, PGRES_COMMAND_OK, PQclear(), PQerrorMessage(), PQexec(), PQresultStatus(), and res.

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 869 of file pgbench.c.

871 {
872  printf("%s is a benchmarking tool for PostgreSQL.\n\n"
873  "Usage:\n"
874  " %s [OPTION]... [DBNAME]\n"
875  "\nInitialization options:\n"
876  " -i, --initialize invokes initialization mode\n"
877  " -I, --init-steps=[" ALL_INIT_STEPS "]+ (default \"" DEFAULT_INIT_STEPS "\")\n"
878  " run selected initialization steps, in the specified order\n"
879  " d: drop any existing pgbench tables\n"
880  " t: create the tables used by the standard pgbench scenario\n"
881  " g: generate data, client-side\n"
882  " G: generate data, server-side\n"
883  " v: invoke VACUUM on the standard tables\n"
884  " p: create primary key indexes on the standard tables\n"
885  " f: create foreign keys between the standard tables\n"
886  " -F, --fillfactor=NUM set fill factor\n"
887  " -n, --no-vacuum do not run VACUUM during initialization\n"
888  " -q, --quiet quiet logging (one message each 5 seconds)\n"
889  " -s, --scale=NUM scaling factor\n"
890  " --foreign-keys create foreign key constraints between tables\n"
891  " --index-tablespace=TABLESPACE\n"
892  " create indexes in the specified tablespace\n"
893  " --partition-method=(range|hash)\n"
894  " partition pgbench_accounts with this method (default: range)\n"
895  " --partitions=NUM partition pgbench_accounts into NUM parts (default: 0)\n"
896  " --tablespace=TABLESPACE create tables in the specified tablespace\n"
897  " --unlogged-tables create tables as unlogged tables\n"
898  "\nOptions to select what to run:\n"
899  " -b, --builtin=NAME[@W] add builtin script NAME weighted at W (default: 1)\n"
900  " (use \"-b list\" to list available scripts)\n"
901  " -f, --file=FILENAME[@W] add script FILENAME weighted at W (default: 1)\n"
902  " -N, --skip-some-updates skip updates of pgbench_tellers and pgbench_branches\n"
903  " (same as \"-b simple-update\")\n"
904  " -S, --select-only perform SELECT-only transactions\n"
905  " (same as \"-b select-only\")\n"
906  "\nBenchmarking options:\n"
907  " -c, --client=NUM number of concurrent database clients (default: 1)\n"
908  " -C, --connect establish new connection for each transaction\n"
909  " -D, --define=VARNAME=VALUE\n"
910  " define variable for use by custom script\n"
911  " -j, --jobs=NUM number of threads (default: 1)\n"
912  " -l, --log write transaction times to log file\n"
913  " -L, --latency-limit=NUM count transactions lasting more than NUM ms as late\n"
914  " -M, --protocol=simple|extended|prepared\n"
915  " protocol for submitting queries (default: simple)\n"
916  " -n, --no-vacuum do not run VACUUM before tests\n"
917  " -P, --progress=NUM show thread progress report every NUM seconds\n"
918  " -r, --report-per-command report latencies, failures, and retries per command\n"
919  " -R, --rate=NUM target rate in transactions per second\n"
920  " -s, --scale=NUM report this scale factor in output\n"
921  " -t, --transactions=NUM number of transactions each client runs (default: 10)\n"
922  " -T, --time=NUM duration of benchmark test in seconds\n"
923  " -v, --vacuum-all vacuum all four standard tables before tests\n"
924  " --aggregate-interval=NUM aggregate data over NUM seconds\n"
925  " --exit-on-abort exit when any client is aborted\n"
926  " --failures-detailed report the failures grouped by basic types\n"
927  " --log-prefix=PREFIX prefix for transaction time log file\n"
928  " (default: \"pgbench_log\")\n"
929  " --max-tries=NUM max number of tries to run transaction (default: 1)\n"
930  " --progress-timestamp use Unix epoch timestamps for progress\n"
931  " --random-seed=SEED set random seed (\"time\", \"rand\", integer)\n"
932  " --sampling-rate=NUM fraction of transactions to log (e.g., 0.01 for 1%%)\n"
933  " --show-script=NAME show builtin script code, then exit\n"
934  " --verbose-errors print messages of all errors\n"
935  "\nCommon options:\n"
936  " --debug print debugging output\n"
937  " -d, --dbname=DBNAME database name to connect to\n"
938  " -h, --host=HOSTNAME database server host or socket directory\n"
939  " -p, --port=PORT database server port number\n"
940  " -U, --username=USERNAME connect as specified database user\n"
941  " -V, --version output version information, then exit\n"
942  " -?, --help show this help, then exit\n"
943  "\n"
944  "Report bugs to <%s>.\n"
945  "%s home page: <%s>\n",
946  progname, progname, PACKAGE_BUGREPORT, PACKAGE_NAME, PACKAGE_URL);

References ALL_INIT_STEPS, DEFAULT_INIT_STEPS, printf, and progname.

Referenced by main().

◆ valid_variable_name()

static bool valid_variable_name ( const char *  name)
static

Definition at line 1737 of file pgbench.c.

1739 {
1740  const unsigned char *ptr = (const unsigned char *) name;
1741 
1742  /* Mustn't be zero-length */
1743  if (*ptr == '\0')
1744  return false;
1745 
1746  /* must not start with [0-9] */
1747  if (IS_HIGHBIT_SET(*ptr) ||
1748  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1749  "_", *ptr) != NULL)
1750  ptr++;
1751  else
1752  return false;
1753 
1754  /* remaining characters can include [0-9] */
1755  while (*ptr)
1756  {
1757  if (IS_HIGHBIT_SET(*ptr) ||
1758  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1759  "_0123456789", *ptr) != NULL)
1760  ptr++;
1761  else
1762  return false;
1763  }
1764 
1765  return true;

References IS_HIGHBIT_SET, and name.

Referenced by lookupCreateVariable().

◆ valueTruth()

static bool valueTruth ( PgBenchValue pval)
static

Definition at line 2023 of file pgbench.c.

2025 {
2026  switch (pval->type)
2027  {
2028  case PGBT_NULL:
2029  return false;
2030  case PGBT_BOOLEAN:
2031  return pval->u.bval;
2032  case PGBT_INT:
2033  return pval->u.ival != 0;
2034  case PGBT_DOUBLE:
2035  return pval->u.dval != 0.0;
2036  default:
2037  /* internal error, unexpected type */
2038  Assert(0);
2039  return false;
2040  }

References Assert, PgBenchValue::bval, PgBenchValue::dval, PgBenchValue::ival, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, PgBenchValue::type, and PgBenchValue::u.

Referenced by evalLazyFunc(), and executeMetaCommand().

◆ valueTypeName()

static char* valueTypeName ( PgBenchValue pval)
static

Definition at line 1981 of file pgbench.c.

1983 {
1984  if (pval->type == PGBT_NO_VALUE)
1985  return "none";
1986  else if (pval->type == PGBT_NULL)
1987  return "null";
1988  else if (pval->type == PGBT_INT)
1989  return "int";
1990  else if (pval->type == PGBT_DOUBLE)
1991  return "double";
1992  else if (pval->type == PGBT_BOOLEAN)
1993  return "boolean";
1994  else
1995  {
1996  /* internal error, should never get there */
1997  Assert(false);
1998  return NULL;
1999  }

References Assert, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NO_VALUE, PGBT_NULL, and PgBenchValue::type.

Referenced by coerceToBool(), coerceToDouble(), and coerceToInt().

◆ wait_on_socket_set()

static int wait_on_socket_set ( socket_set sa,
int64  usecs 
)
static

Definition at line 7903 of file pgbench.c.

7905 {
7906  if (usecs > 0)
7907  {
7908  struct timeval timeout;
7909 
7910  timeout.tv_sec = usecs / 1000000;
7911  timeout.tv_usec = usecs % 1000000;
7912  return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
7913  }
7914  else
7915  {
7916  return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
7917  }
#define select(n, r, w, e, timeout)
Definition: win32_port.h:495

References select.

Referenced by threadRun().

Variable Documentation

◆ agg_interval

int agg_interval

Definition at line 258 of file pgbench.c.

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

◆ barrier

◆ base_random_sequence

pg_prng_state base_random_sequence
static

Definition at line 476 of file pgbench.c.

Referenced by initRandomState(), main(), and set_random_seed().

◆ builtin_script

const BuiltinScript builtin_script[]
static

Definition at line 779 of file pgbench.c.

Referenced by findBuiltin(), and listAvailableScripts().

◆ dbName

const char* dbName = NULL

Definition at line 297 of file pgbench.c.

Referenced by doConnect(), main(), pg_database_size_name(), and PQsetdbLogin().

◆ duration

int duration = 0

◆ end_time

int64 end_time = 0

◆ epoch_shift

pg_time_usec_t epoch_shift

Definition at line 448 of file pgbench.c.

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

◆ exit_on_abort

bool exit_on_abort = false
static

Definition at line 769 of file pgbench.c.

Referenced by main(), and threadRun().

◆ failures_detailed

bool failures_detailed = false

Definition at line 291 of file pgbench.c.

Referenced by doLog(), getResultString(), main(), and printResults().

◆ fillfactor

◆ index_tablespace

char* index_tablespace = NULL

Definition at line 217 of file pgbench.c.

Referenced by initCreatePKeys(), and main().

◆ is_connect

bool is_connect

Definition at line 265 of file pgbench.c.

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

◆ latency_limit

◆ logfile_prefix

char* logfile_prefix = NULL

Definition at line 298 of file pgbench.c.

Referenced by main(), and threadRun().

◆ main_pid

int main_pid

Definition at line 269 of file pgbench.c.

Referenced by main(), and threadRun().

◆ max_tries

uint32 max_tries = 1

◆ nclients

int nclients = 1

Definition at line 263 of file pgbench.c.

Referenced by main(), and printResults().

◆ nthreads

int nthreads = 1

Definition at line 264 of file pgbench.c.

Referenced by main(), printProgressReport(), and printResults().

◆ num_scripts

int num_scripts
static

Definition at line 764 of file pgbench.c.

Referenced by addScript(), allocCStatePrepared(), chooseScript(), main(), and printResults().

◆ nxacts

int nxacts = 0

Definition at line 173 of file pgbench.c.

Referenced by advanceConnectionState(), main(), and printResults().

◆ partition_method

partition_method_t partition_method = PART_NONE
static

Definition at line 233 of file pgbench.c.

Referenced by createPartitions(), GetTableInfo(), initCreateTables(), main(), and printResults().

◆ PARTITION_METHOD

const char* const PARTITION_METHOD[] = {"none", "range", "hash"}
static

Definition at line 234 of file pgbench.c.

Referenced by initCreateTables(), and printResults().

◆ partitions

int partitions = 0
static

◆ per_script_stats

bool per_script_stats = false

Definition at line 260 of file pgbench.c.

Referenced by main(), printResults(), and processXactStats().

◆ pgbench_callbacks

const PsqlScanCallbacks pgbench_callbacks
static
Initial value:
= {
NULL,
}

Definition at line 845 of file pgbench.c.

Referenced by ParseScript().

◆ pghost

const char* pghost = NULL

Definition at line 294 of file pgbench.c.

Referenced by connectDatabase(), doConnect(), initialize_environment(), main(), and PQsetdbLogin().

◆ pgport

const char* pgport = NULL

Definition at line 295 of file pgbench.c.

Referenced by connectDatabase(), doConnect(), initialize_environment(), main(), and PQsetdbLogin().

◆ progname

const char* progname

Definition at line 299 of file pgbench.c.

Referenced by doConnect(), main(), and usage().

◆ progress

◆ progress_timestamp

bool progress_timestamp = false

Definition at line 262 of file pgbench.c.

Referenced by main(), and printProgressReport().

◆ querymode

QueryMode querymode = QUERY_SIMPLE
static

◆ QUERYMODE

const char* const QUERYMODE[] = {"simple", "extended", "prepared"}
static

Definition at line 713 of file pgbench.c.

Referenced by main(), and printResults().

◆ random_seed

int64 random_seed = -1

Definition at line 237 of file pgbench.c.

Referenced by main(), and set_random_seed().

◆ report_per_command

bool report_per_command = false

Definition at line 266 of file pgbench.c.

Referenced by advanceConnectionState(), main(), and printResults().

◆ sample_rate

double sample_rate = 0.0

Definition at line 197 of file pgbench.c.

Referenced by doLog(), and main().

◆ scale

◆ sql_script

◆ tablespace

◆ throttle_delay

double throttle_delay = 0

◆ timer_exceeded

volatile sig_atomic_t timer_exceeded = false

Definition at line 303 of file pgbench.c.

Referenced by advanceConnectionState(), doRetry(), handle_sig_alarm(), and runShellCommand().

◆ total_weight

int64 total_weight = 0
static

Definition at line 765 of file pgbench.c.

Referenced by chooseScript(), main(), and printResults().

◆ unlogged_tables

bool unlogged_tables = false

Definition at line 192 of file pgbench.c.

Referenced by createPartitions(), initCreateTables(), and main().

◆ use_log

bool use_log

Definition at line 256 of file pgbench.c.

Referenced by doLog(), main(), processXactStats(), and threadRun().

◆ use_quiet

bool use_quiet

Definition at line 257 of file pgbench.c.

Referenced by initPopulateTable(), and main().

◆ username

◆ verbose_errors

bool verbose_errors = false
static

Definition at line 767 of file pgbench.c.

Referenced by advanceConnectionState(), main(), and readCommandResponse().