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

static int nxacts = 0
 
static int duration = 0
 
static int64 end_time = 0
 
static int scale = 1
 
static int fillfactor = 100
 
static bool unlogged_tables = false
 
static double sample_rate = 0.0
 
static double throttle_delay = 0
 
static int64 latency_limit = 0
 
static char * tablespace = NULL
 
static 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"}
 
static int64 random_seed = -1
 
static bool use_log
 
static bool use_quiet
 
static int agg_interval
 
static bool per_script_stats = false
 
static int progress = 0
 
static bool progress_timestamp = false
 
static int nclients = 1
 
static int nthreads = 1
 
static bool is_connect
 
static bool report_per_command = false
 
static int main_pid
 
static uint32 max_tries = 1
 
static bool failures_detailed = false
 
static const char * pghost = NULL
 
static const char * pgport = NULL
 
static const char * username = NULL
 
static const char * dbName = NULL
 
static char * logfile_prefix = NULL
 
static const char * progname
 
static volatile sig_atomic_t timer_exceeded = false
 
static 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 685 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2242 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 347 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 679 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 867 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 348 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 678 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 310 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 843 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 370 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 485 of file pgbench.c.

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 454 of file pgbench.c.

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

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

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

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

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

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 468 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1451 of file pgbench.c.

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

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

7881 {
7882  /* See connect_slot() for background on this code. */
7883 #ifdef WIN32
7884  if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7885  {
7886  pg_log_error("too many concurrent database clients for this platform: %d",
7887  sa->fds.fd_count + 1);
7888  exit(1);
7889  }
7890 #else
7891  if (fd < 0 || fd >= FD_SETSIZE)
7892  {
7893  pg_log_error("socket file descriptor out of range for select(): %d",
7894  fd);
7895  pg_log_error_hint("Try fewer concurrent database clients.");
7896  exit(1);
7897  }
7898 #endif
7899  FD_SET(fd, &sa->fds);
7900  if (fd > sa->maxfd)
7901  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 6193 of file pgbench.c.

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

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

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

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

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

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

7862 {
7863  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 3069 of file pgbench.c.

3071 {
3072  Assert(st->prepared == NULL);
3073 
3074  st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3075  for (int i = 0; i < num_scripts; i++)
3076  {
3077  ParsedScript *script = &sql_script[i];
3078  int numcmds;
3079 
3080  for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3081  ;
3082  st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3083  }
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 1936 of file pgbench.c.

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

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3225 of file pgbench.c.

3227 {
3228  return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3229  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 5855 of file pgbench.c.

5857 {
5858  /* statically check conditional structure */
5860  int i;
5861 
5862  for (i = 0; ps->commands[i] != NULL; i++)
5863  {
5864  Command *cmd = ps->commands[i];
5865 
5866  if (cmd->type == META_COMMAND)
5867  {
5868  switch (cmd->meta)
5869  {
5870  case META_IF:
5872  break;
5873  case META_ELIF:
5874  if (conditional_stack_empty(cs))
5875  ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5877  ConditionError(ps->desc, i + 1, "\\elif after \\else");
5878  break;
5879  case META_ELSE:
5880  if (conditional_stack_empty(cs))
5881  ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5883  ConditionError(ps->desc, i + 1, "\\else after \\else");
5885  break;
5886  case META_ENDIF:
5887  if (!conditional_stack_pop(cs))
5888  ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5889  break;
5890  default:
5891  /* ignore anything else... */
5892  break;
5893  }
5894  }
5895  }
5896  if (!conditional_stack_empty(cs))
5897  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:5845

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

5205 {
5206  if (initialize_steps[0] == '\0')
5207  pg_fatal("no initialization steps specified");
5208 
5209  for (const char *step = initialize_steps; *step != '\0'; step++)
5210  {
5211  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5212  {
5213  pg_log_error("unrecognized initialization step \"%c\"", *step);
5214  pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5215  exit(1);
5216  }
5217  }
#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 3047 of file pgbench.c.

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

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

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

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 2004 of file pgbench.c.

2006 {
2007  if (pval->type == PGBT_BOOLEAN)
2008  {
2009  *bval = pval->u.bval;
2010  return true;
2011  }
2012  else /* NULL, INT or DOUBLE */
2013  {
2014  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2015  *bval = false; /* suppress uninitialized-variable warnings */
2016  return false;
2017  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1982
@ 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 2073 of file pgbench.c.

2075 {
2076  if (pval->type == PGBT_DOUBLE)
2077  {
2078  *dval = pval->u.dval;
2079  return true;
2080  }
2081  else if (pval->type == PGBT_INT)
2082  {
2083  *dval = (double) pval->u.ival;
2084  return true;
2085  }
2086  else /* BOOLEAN or NULL */
2087  {
2088  pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2089  return false;
2090  }
@ 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 2045 of file pgbench.c.

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

3040 {
3042  pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3043  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 3028 of file pgbench.c.

3030 {
3031  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3032  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 1596 of file pgbench.c.

1598 {
1599  return strcmp(((const Variable *) v1)->name,
1600  ((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 1201 of file pgbench.c.

1203 {
1204  double b = pow(2.0, s - 1.0);
1205  double x,
1206  t,
1207  u,
1208  v;
1209 
1210  /* Ensure n is sane */
1211  if (n <= 1)
1212  return 1;
1213 
1214  while (true)
1215  {
1216  /* random variates */
1217  u = pg_prng_double(state);
1218  v = pg_prng_double(state);
1219 
1220  x = floor(pow(u, -1.0 / (s - 1.0)));
1221 
1222  t = pow(1.0 + 1.0 / x, s - 1.0);
1223  /* reject if too large or out of bound */
1224  if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1225  break;
1226  }
1227  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 5845 of file pgbench.c.

5847 {
5848  pg_fatal("condition error in script \"%s\" command %d: %s",
5849  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 5549 of file pgbench.c.

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

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

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

3476 {
3477  /* send a sync */
3478  if (!PQpipelineSync(st->con))
3479  {
3480  pg_log_error("client %d aborted: failed to send a pipeline sync",
3481  st->id);
3482  return 0;
3483  }
3484 
3485  /* receive PGRES_PIPELINE_SYNC and null following it */
3486  for (;;)
3487  {
3488  PGresult *res = PQgetResult(st->con);
3489 
3491  {
3492  PQclear(res);
3493  res = PQgetResult(st->con);
3494  Assert(res == NULL);
3495  break;
3496  }
3497  PQclear(res);
3498  }
3499 
3500  /* exit pipeline */
3501  if (PQexitPipelineMode(st->con) != 1)
3502  {
3503  pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3504  st->id);
3505  return 0;
3506  }
3507  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:113

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

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

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1531 of file pgbench.c.

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

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

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

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

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

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

2824 {
2825  if (isLazyFunc(func))
2826  return evalLazyFunc(st, func, args, retval);
2827  else
2828  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2125
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2132
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2249

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

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

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

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

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

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

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

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

1502 {
1503  PGresult *res;
1504 
1505  res = PQexec(con, sql);
1507  {
1508  pg_log_error("query failed: %s", PQerrorMessage(con));
1509  pg_log_error_detail("Query was: %s", sql);
1510  exit(1);
1511  }
1512  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 6120 of file pgbench.c.

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

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

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

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5578 of file pgbench.c.

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

7868 {
7869  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 1113 of file pgbench.c.

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

4506 {
4507  return (stats->serialization_failures +
4508  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 1137 of file pgbench.c.

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

1247 {
1248  int64 result;
1249  int i;
1250 
1251  result = FNV_OFFSET_BASIS ^ seed;
1252  for (i = 0; i < 8; ++i)
1253  {
1254  int32 octet = val & 0xff;
1255 
1256  val = val >> 8;
1257  result = result ^ octet;
1258  result = result * FNV_PRIME;
1259  }
1260 
1261  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 1270 of file pgbench.c.

1272 {
1273  uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1274  uint64 k = (uint64) val;
1275 
1276  k *= MM2_MUL;
1277  k ^= k >> MM2_ROT;
1278  k *= MM2_MUL;
1279 
1280  result ^= k;
1281  result *= MM2_MUL;
1282 
1283  result ^= result >> MM2_ROT;
1284  result *= MM2_MUL;
1285  result ^= result >> MM2_ROT;
1286 
1287  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 2880 of file pgbench.c.

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

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

1181 {
1182  /*
1183  * Use inverse transform sampling to generate a value > 0, such that the
1184  * expected (i.e. average) value is the given argument.
1185  */
1186  double uniform;
1187 
1188  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1189  uniform = 1.0 - pg_prng_double(state);
1190 
1191  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 1972 of file pgbench.c.

1975 {
1976  int i;
1977 
1978  for (i = 0; i < command->argc - 1; i++)
1979  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 1102 of file pgbench.c.

1104 {
1105  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 4515 of file pgbench.c.

4517 {
4518  if (skipped)
4519  return "skipped";
4520  else if (failures_detailed)
4521  {
4522  switch (estatus)
4523  {
4525  return "serialization";
4527  return "deadlock";
4528  default:
4529  /* internal error which should never occur */
4530  pg_fatal("unexpected error status: %d", estatus);
4531  }
4532  }
4533  else
4534  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 3208 of file pgbench.c.

3210 {
3211  if (sqlState != NULL)
3212  {
3213  if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3215  else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3216  return ESTATUS_DEADLOCK_ERROR;
3217  }
3218 
3219  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 5308 of file pgbench.c.

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

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

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

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

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

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

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

7713 {
7714  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4931 of file pgbench.c.

4933 {
4934  /* "filler" column defaults to blank padded empty string */
4935  printfPQExpBuffer(sql,
4936  INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4937  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 4913 of file pgbench.c.

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

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5177 of file pgbench.c.

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

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5139 of file pgbench.c.

5141 {
5142  static const char *const DDLINDEXes[] = {
5143  "alter table pgbench_branches add primary key (bid)",
5144  "alter table pgbench_tellers add primary key (tid)",
5145  "alter table pgbench_accounts add primary key (aid)"
5146  };
5147  int i;
5148  PQExpBufferData query;
5149 
5150  fprintf(stderr, "creating primary keys...\n");
5151  initPQExpBuffer(&query);
5152 
5153  for (i = 0; i < lengthof(DDLINDEXes); i++)
5154  {
5155  resetPQExpBuffer(&query);
5156  appendPQExpBufferStr(&query, DDLINDEXes[i]);
5157 
5158  if (index_tablespace != NULL)
5159  {
5160  char *escape_tablespace;
5161 
5162  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5163  strlen(index_tablespace));
5164  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5165  PQfreemem(escape_tablespace);
5166  }
5167 
5168  executeStatement(con, query.data);
5169  }
5170 
5171  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
static 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 4808 of file pgbench.c.

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

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

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5049 of file pgbench.c.

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

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

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

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

1090 {
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:477

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

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1394 of file pgbench.c.

1396 {
1397  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 4922 of file pgbench.c.

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

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4903 of file pgbench.c.

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

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5126 of file pgbench.c.

5128 {
5129  fprintf(stderr, "vacuuming...\n");
5130  executeStatement(con, "vacuum analyze pgbench_branches");
5131  executeStatement(con, "vacuum analyze pgbench_tellers");
5132  executeStatement(con, "vacuum analyze pgbench_accounts");
5133  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 951 of file pgbench.c.

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

References str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 2125 of file pgbench.c.

2127 {
2128  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 6108 of file pgbench.c.

6110 {
6111  int i;
6112 
6113  fprintf(stderr, "Available builtin scripts:\n");
6114  for (i = 0; i < lengthof(builtin_script); i++)
6115  fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6116  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 1792 of file pgbench.c.

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

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

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

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

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

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

1420 {
1421  if (acc->count == 0 || ss->min < acc->min)
1422  acc->min = ss->min;
1423  if (acc->count == 0 || ss->max > acc->max)
1424  acc->max = ss->max;
1425  acc->count += ss->count;
1426  acc->sum += ss->sum;
1427  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 5417 of file pgbench.c.

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

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

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

1891 {
1892  int i = 1; /* starting at 1 skips the colon */
1893  char *name;
1894 
1895  /* keep this logic in sync with valid_variable_name() */
1896  if (IS_HIGHBIT_SET(sql[i]) ||
1897  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1898  "_", sql[i]) != NULL)
1899  i++;
1900  else
1901  return NULL;
1902 
1903  while (IS_HIGHBIT_SET(sql[i]) ||
1904  strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1905  "_0123456789", sql[i]) != NULL)
1906  i++;
1907 
1908  name = pg_malloc(i);
1909  memcpy(name, &sql[1], i - 1);
1910  name[i - 1] = '\0';
1911 
1912  *eaten = i;
1913  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 1303 of file pgbench.c.

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

853 {
854  instr_time now;
855 
857 
#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 861 of file pgbench.c.

863 {
864  if ((*now) == 0)
865  (*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 5598 of file pgbench.c.

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

3091 {
3092  Command *command = sql_script[st->use_file].commands[command_num];
3093 
3094  /* No prepare for non-SQL commands */
3095  if (command->type != SQL_COMMAND)
3096  return;
3097 
3098  if (!st->prepared)
3099  allocCStatePrepared(st);
3100 
3101  if (!st->prepared[st->use_file][command_num])
3102  {
3103  PGresult *res;
3104 
3105  pg_log_debug("client %d preparing %s", st->id, command->prepname);
3106  res = PQprepare(st->con, command->prepname,
3107  command->argv[0], command->argc - 1, NULL);
3109  pg_log_error("%s", PQerrorMessage(st->con));
3110  PQclear(res);
3111  st->prepared[st->use_file][command_num] = true;
3112  }
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:3069

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

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

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

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

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

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

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

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

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

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

6324 {
6325  int server_ver = PQserverVersion(con);
6326  int client_ver = PG_VERSION_NUM;
6327 
6328  if (server_ver != client_ver)
6329  {
6330  const char *server_version;
6331  char sverbuf[32];
6332 
6333  /* Try to get full text form, might include "devel" etc */
6334  server_version = PQparameterStatus(con, "server_version");
6335  /* Otherwise fall back on server_ver */
6336  if (!server_version)
6337  {
6338  formatPGVersionNumber(server_ver, true,
6339  sverbuf, sizeof(sverbuf));
6340  server_version = sverbuf;
6341  }
6342 
6343  printf(_("%s (%s, server %s)\n"),
6344  "pgbench", PG_VERSION, server_version);
6345  }
6346  /* For version match, only print pgbench version */
6347  else
6348  printf("%s (%s)\n", "pgbench", PG_VERSION);
6349  fflush(stdout);
#define _(x)
Definition: elog.c:90
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7136
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 5635 of file pgbench.c.

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

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

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

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

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

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

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

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

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

1874 {
1875  PgBenchValue val;
1876 
1877  setIntValue(&val, value);
1878  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 1852 of file pgbench.c.

1855 {
1856  Variable *var;
1857 
1858  var = lookupCreateVariable(variables, context, name);
1859  if (!var)
1860  return false;
1861 
1862  free(var->svalue);
1863  var->svalue = NULL;
1864  var->value = *value;
1865 
1866  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 6042 of file pgbench.c.

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

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

1918 {
1919  int valueln = strlen(value);
1920 
1921  if (valueln > len)
1922  {
1923  size_t offset = param - *sql;
1924 
1925  *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1926  param = *sql + offset;
1927  }
1928 
1929  if (valueln != len)
1930  memmove(param + valueln, param + len, strlen(param + len) + 1);
1931  memcpy(param, value, valueln);
1932 
1933  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 5223 of file pgbench.c.

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

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

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

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

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

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

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

7719 {
7721  alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7711
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 2102 of file pgbench.c.

2104 {
2105  pv->type = PGBT_BOOLEAN;
2106  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 2118 of file pgbench.c.

2120 {
2121  pv->type = PGBT_DOUBLE;
2122  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 2110 of file pgbench.c.

2112 {
2113  pv->type = PGBT_INT;
2114  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 2094 of file pgbench.c.

2096 {
2097  pv->type = PGBT_NULL;
2098  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 5514 of file pgbench.c.

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

7923 {
7924  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 1059 of file pgbench.c.

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

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

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

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

1518 {
1519  PGresult *res;
1520 
1521  res = PQexec(con, sql);
1523  {
1524  pg_log_error("%s", PQerrorMessage(con));
1525  pg_log_error_detail("(ignoring this error and continuing anyway)");
1526  }
1527  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 870 of file pgbench.c.

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

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

References IS_HIGHBIT_SET, and name.

Referenced by lookupCreateVariable().

◆ valueTruth()

static bool valueTruth ( PgBenchValue pval)
static

Definition at line 2024 of file pgbench.c.

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

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

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

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

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

References select.

Referenced by threadRun().

Variable Documentation

◆ agg_interval

int agg_interval
static

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

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

◆ builtin_script

const BuiltinScript builtin_script[]
static

Definition at line 780 of file pgbench.c.

Referenced by findBuiltin(), and listAvailableScripts().

◆ dbName

const char* dbName = NULL
static

Definition at line 297 of file pgbench.c.

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

◆ duration

int duration = 0
static

◆ end_time

◆ epoch_shift

pg_time_usec_t epoch_shift
static

Definition at line 449 of file pgbench.c.

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

◆ exit_on_abort

bool exit_on_abort = false
static

Definition at line 770 of file pgbench.c.

Referenced by main(), and threadRun().

◆ failures_detailed

bool failures_detailed = false
static

Definition at line 291 of file pgbench.c.

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

◆ fillfactor

◆ index_tablespace

char* index_tablespace = NULL
static

Definition at line 217 of file pgbench.c.

Referenced by initCreatePKeys(), and main().

◆ is_connect

bool is_connect
static

Definition at line 265 of file pgbench.c.

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

◆ latency_limit

int64 latency_limit = 0
static

◆ logfile_prefix

char* logfile_prefix = NULL
static

Definition at line 298 of file pgbench.c.

Referenced by main(), and threadRun().

◆ main_pid

int main_pid
static

Definition at line 269 of file pgbench.c.

Referenced by main(), and threadRun().

◆ max_tries

uint32 max_tries = 1
static

◆ nclients

int nclients = 1
static

Definition at line 263 of file pgbench.c.

Referenced by main(), and printResults().

◆ nthreads

int nthreads = 1
static

Definition at line 264 of file pgbench.c.

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

◆ num_scripts

int num_scripts
static

Definition at line 765 of file pgbench.c.

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

◆ nxacts

int nxacts = 0
static

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
static

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

Referenced by ParseScript().

◆ pghost

const char* pghost = NULL
static

Definition at line 294 of file pgbench.c.

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

◆ pgport

const char* pgport = NULL
static

Definition at line 295 of file pgbench.c.

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

◆ progname

const char* progname
static

Definition at line 299 of file pgbench.c.

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

◆ progress

◆ progress_timestamp

bool progress_timestamp = false
static

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

Referenced by main(), and printResults().

◆ random_seed

int64 random_seed = -1
static

Definition at line 237 of file pgbench.c.

Referenced by main(), and set_random_seed().

◆ report_per_command

bool report_per_command = false
static

Definition at line 266 of file pgbench.c.

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

◆ sample_rate

double sample_rate = 0.0
static

Definition at line 197 of file pgbench.c.

Referenced by doLog(), and main().

◆ scale

◆ sql_script

◆ tablespace

◆ throttle_delay

double throttle_delay = 0
static

◆ timer_exceeded

volatile sig_atomic_t timer_exceeded = false
static

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

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

◆ unlogged_tables

bool unlogged_tables = false
static

Definition at line 192 of file pgbench.c.

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

◆ use_log

bool use_log
static

Definition at line 256 of file pgbench.c.

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

◆ use_quiet

bool use_quiet
static

Definition at line 257 of file pgbench.c.

Referenced by initPopulateTable(), and main().

◆ username

const char* username = NULL
static

Definition at line 296 of file pgbench.c.

Referenced by doConnect(), and main().

◆ verbose_errors

bool verbose_errors = false
static

Definition at line 768 of file pgbench.c.

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