Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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 "catalog/pg_class_d.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 char get_table_relkind (PGconn *con, const char *table)
 
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)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source, int lineno, int start_offset)
 
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 164 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 163 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 167 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 78 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 77 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 79 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 85 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 84 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 166 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 74 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 686 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2268 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 348 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 172 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 680 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 169 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 171 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 86 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 87 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 88 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 246 of file pgbench.c.

◆ nbranches

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

Definition at line 244 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 245 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 893 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 255 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

Definition at line 349 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 107 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 679 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

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

Definition at line 156 of file pgbench.c.

◆ THREAD_BARRIER_INIT

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

Definition at line 153 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   pthread_barrier_t

Definition at line 152 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

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

Definition at line 155 of file pgbench.c.

◆ THREAD_CREATE

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

Definition at line 148 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 147 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 146 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 145 of file pgbench.c.

◆ THREAD_JOIN

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

Definition at line 150 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   pthread_t

Definition at line 144 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 311 of file pgbench.c.

◆ WSEP

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

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

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

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

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 455 of file pgbench.c.

457{
460
461 /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:462
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:458
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:463
@ ESTATUS_NO_ERROR
Definition: pgbench.c:457
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:461

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

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

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 227 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 706 of file pgbench.c.

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

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 469 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1477 of file pgbench.c.

1480{
1481 /* Record the skipped transaction */
1482 if (skipped)
1483 {
1484 /* no latency to record on skipped transactions */
1485 stats->skipped++;
1486 return;
1487 }
1488
1489 /*
1490 * Record the number of retries regardless of whether the transaction was
1491 * successful or failed.
1492 */
1493 if (tries > 1)
1494 {
1495 stats->retries += (tries - 1);
1496 stats->retried++;
1497 }
1498
1499 switch (estatus)
1500 {
1501 /* Record the successful transaction */
1502 case ESTATUS_NO_ERROR:
1503 stats->cnt++;
1504
1505 addToSimpleStats(&stats->latency, lat);
1506
1507 /* and possibly the same for schedule lag */
1508 if (throttle_delay)
1509 addToSimpleStats(&stats->lag, lag);
1510 break;
1511
1512 /* Record the failed transaction */
1514 stats->serialization_failures++;
1515 break;
1517 stats->deadlock_failures++;
1518 break;
1519 default:
1520 /* internal error which should never occur */
1521 pg_fatal("unexpected error status: %d", estatus);
1522 }
#define pg_fatal(...)
static double throttle_delay
Definition: pgbench.c:204
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1429
int64 serialization_failures
Definition: pgbench.c:436
int64 cnt
Definition: pgbench.c:426
int64 retried
Definition: pgbench.c:432
int64 deadlock_failures
Definition: pgbench.c:439
int64 skipped
Definition: pgbench.c:428
SimpleStats lag
Definition: pgbench.c:443
int64 retries
Definition: pgbench.c:430
SimpleStats latency
Definition: pgbench.c:442

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

7955{
7956 /* See connect_slot() for background on this code. */
7957#ifdef WIN32
7958 if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7959 {
7960 pg_log_error("too many concurrent database clients for this platform: %d",
7961 sa->fds.fd_count + 1);
7962 exit(1);
7963 }
7964#else
7965 if (fd < 0 || fd >= FD_SETSIZE)
7966 {
7967 pg_log_error("socket file descriptor out of range for select(): %d",
7968 fd);
7969 pg_log_error_hint("Try fewer concurrent database clients.");
7970 exit(1);
7971 }
7972#endif
7973 FD_SET(fd, &sa->fds);
7974 if (fd > sa->maxfd)
7975 sa->maxfd = fd;
#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 fd(), pg_log_error, and pg_log_error_hint.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6247 of file pgbench.c.

6249{
6250 if (script->commands == NULL || script->commands[0] == NULL)
6251 pg_fatal("empty command list for script \"%s\"", script->desc);
6252
6253 if (num_scripts >= MAX_SCRIPTS)
6254 pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6255
6256 CheckConditional(script);
6257
6258 sql_script[num_scripts] = *script;
6259 num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5905
#define MAX_SCRIPTS
Definition: pgbench.c:348
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:765
static int num_scripts
Definition: pgbench.c:766
const char * desc
Definition: pgbench.c:759
Command ** commands
Definition: pgbench.c:761

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

1431{
1432 if (ss->count == 0 || val < ss->min)
1433 ss->min = val;
1434 if (ss->count == 0 || val > ss->max)
1435 ss->max = val;
1436 ss->count++;
1437 ss->sum += val;
1438 ss->sum2 += val * val;
long val
Definition: informix.c:689
int64 count
Definition: pgbench.c:359
double sum
Definition: pgbench.c:362
double min
Definition: pgbench.c:360
double max
Definition: pgbench.c:361
double sum2
Definition: pgbench.c:363

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

3632{
3633
3634 /*
3635 * gettimeofday() isn't free, so we get the current timestamp lazily the
3636 * first time it's needed, and reuse the same value throughout this
3637 * function after that. This also ensures that e.g. the calculated
3638 * latency reported in the log file and in the totals are the same. Zero
3639 * means "not set yet". Reset "now" when we execute shell commands or
3640 * expressions, which might take a non-negligible amount of time, though.
3641 */
3642 pg_time_usec_t now = 0;
3643
3644 /*
3645 * Loop in the state machine, until we have to wait for a result from the
3646 * server or have to sleep for throttling or \sleep.
3647 *
3648 * Note: In the switch-statement below, 'break' will loop back here,
3649 * meaning "continue in the state machine". Return is used to return to
3650 * the caller, giving the thread the opportunity to advance another
3651 * client.
3652 */
3653 for (;;)
3654 {
3655 Command *command;
3656
3657 switch (st->state)
3658 {
3659 /* Select transaction (script) to run. */
3661 st->use_file = chooseScript(thread);
3663
3664 /* reset transaction variables to default values */
3666 st->tries = 1;
3667
3668 pg_log_debug("client %d executing script \"%s\"",
3669 st->id, sql_script[st->use_file].desc);
3670
3671 /*
3672 * If time is over, we're done; otherwise, get ready to start
3673 * a new transaction, or to get throttled if that's requested.
3674 */
3677 break;
3678
3679 /* Start new transaction (script) */
3680 case CSTATE_START_TX:
3682
3683 /* establish connection if needed, i.e. under --connect */
3684 if (st->con == NULL)
3685 {
3687
3688 if ((st->con = doConnect()) == NULL)
3689 {
3690 /*
3691 * as the bench is already running, we do not abort
3692 * the process
3693 */
3694 pg_log_error("client %d aborted while establishing connection", st->id);
3695 st->state = CSTATE_ABORTED;
3696 break;
3697 }
3698
3699 /* reset now after connection */
3700 now = pg_time_now();
3701
3702 thread->conn_duration += now - start;
3703
3704 /* Reset session-local state */
3705 pg_free(st->prepared);
3706 st->prepared = NULL;
3707 }
3708
3709 /*
3710 * It is the first try to run this transaction. Remember the
3711 * random state: maybe it will get an error and we will need
3712 * to run it again.
3713 */
3714 st->random_state = st->cs_func_rs;
3715
3716 /* record transaction start time */
3717 st->txn_begin = now;
3718
3719 /*
3720 * When not throttling, this is also the transaction's
3721 * scheduled start time.
3722 */
3723 if (!throttle_delay)
3724 st->txn_scheduled = now;
3725
3726 /* Begin with the first command */
3728 st->command = 0;
3729 break;
3730
3731 /*
3732 * Handle throttling once per transaction by sleeping.
3733 */
3735
3736 /*
3737 * Generate a delay such that the series of delays will
3738 * approximate a Poisson distribution centered on the
3739 * throttle_delay time.
3740 *
3741 * If transactions are too slow or a given wait is shorter
3742 * than a transaction, the next transaction will start right
3743 * away.
3744 */
3746
3747 thread->throttle_trigger +=
3749 st->txn_scheduled = thread->throttle_trigger;
3750
3751 /*
3752 * If --latency-limit is used, and this slot is already late
3753 * so that the transaction will miss the latency limit even if
3754 * it completed immediately, skip this time slot and loop to
3755 * reschedule.
3756 */
3757 if (latency_limit)
3758 {
3760
3761 if (thread->throttle_trigger < now - latency_limit)
3762 {
3763 processXactStats(thread, st, &now, true, agg);
3764
3765 /*
3766 * Finish client if -T or -t was exceeded.
3767 *
3768 * Stop counting skipped transactions under -T as soon
3769 * as the timer is exceeded. Because otherwise it can
3770 * take a very long time to count all of them
3771 * especially when quite a lot of them happen with
3772 * unrealistically high rate setting in -R, which
3773 * would prevent pgbench from ending immediately.
3774 * Because of this behavior, note that there is no
3775 * guarantee that all skipped transactions are counted
3776 * under -T though there is under -t. This is OK in
3777 * practice because it's very unlikely to happen with
3778 * realistic setting.
3779 */
3780 if (timer_exceeded || (nxacts > 0 && st->cnt >= nxacts))
3781 st->state = CSTATE_FINISHED;
3782
3783 /* Go back to top of loop with CSTATE_PREPARE_THROTTLE */
3784 break;
3785 }
3786 }
3787
3788 /*
3789 * stop client if next transaction is beyond pgbench end of
3790 * execution; otherwise, throttle it.
3791 */
3792 st->state = end_time > 0 && st->txn_scheduled > end_time ?
3794 break;
3795
3796 /*
3797 * Wait until it's time to start next transaction.
3798 */
3799 case CSTATE_THROTTLE:
3801
3802 if (now < st->txn_scheduled)
3803 return; /* still sleeping, nothing to do here */
3804
3805 /* done sleeping, but don't start transaction if we're done */
3807 break;
3808
3809 /*
3810 * Send a command to server (or execute a meta-command)
3811 */
3813 command = sql_script[st->use_file].commands[st->command];
3814
3815 /*
3816 * Transition to script end processing if done, but close up
3817 * shop if a pipeline is open at this point.
3818 */
3819 if (command == NULL)
3820 {
3822 st->state = CSTATE_END_TX;
3823 else
3824 {
3825 pg_log_error("client %d aborted: end of script reached with pipeline open",
3826 st->id);
3827 st->state = CSTATE_ABORTED;
3828 }
3829
3830 break;
3831 }
3832
3833 /* record begin time of next command, and initiate it */
3835 {
3837 st->stmt_begin = now;
3838 }
3839
3840 /* Execute the command */
3841 if (command->type == SQL_COMMAND)
3842 {
3843 /* disallow \aset and \gset in pipeline mode */
3845 {
3846 if (command->meta == META_GSET)
3847 {
3848 commandFailed(st, "gset", "\\gset is not allowed in pipeline mode");
3849 st->state = CSTATE_ABORTED;
3850 break;
3851 }
3852 else if (command->meta == META_ASET)
3853 {
3854 commandFailed(st, "aset", "\\aset is not allowed in pipeline mode");
3855 st->state = CSTATE_ABORTED;
3856 break;
3857 }
3858 }
3859
3860 if (!sendCommand(st, command))
3861 {
3862 commandFailed(st, "SQL", "SQL command send failed");
3863 st->state = CSTATE_ABORTED;
3864 }
3865 else
3866 {
3867 /* Wait for results, unless in pipeline mode */
3870 else
3872 }
3873 }
3874 else if (command->type == META_COMMAND)
3875 {
3876 /*-----
3877 * Possible state changes when executing meta commands:
3878 * - on errors CSTATE_ABORTED
3879 * - on sleep CSTATE_SLEEP
3880 * - else CSTATE_END_COMMAND
3881 */
3882 st->state = executeMetaCommand(st, &now);
3883 if (st->state == CSTATE_ABORTED)
3885 }
3886
3887 /*
3888 * We're now waiting for an SQL command to complete, or
3889 * finished processing a metacommand, or need to sleep, or
3890 * something bad happened.
3891 */
3893 st->state == CSTATE_END_COMMAND ||
3894 st->state == CSTATE_SLEEP ||
3895 st->state == CSTATE_ABORTED);
3896 break;
3897
3898 /*
3899 * non executed conditional branch
3900 */
3903 /* quickly skip commands until something to do... */
3904 while (true)
3905 {
3906 command = sql_script[st->use_file].commands[st->command];
3907
3908 /* cannot reach end of script in that state */
3909 Assert(command != NULL);
3910
3911 /*
3912 * if this is conditional related, update conditional
3913 * state
3914 */
3915 if (command->type == META_COMMAND &&
3916 (command->meta == META_IF ||
3917 command->meta == META_ELIF ||
3918 command->meta == META_ELSE ||
3919 command->meta == META_ENDIF))
3920 {
3921 switch (conditional_stack_peek(st->cstack))
3922 {
3923 case IFSTATE_FALSE:
3924 if (command->meta == META_IF)
3925 {
3926 /* nested if in skipped branch - ignore */
3929 st->command++;
3930 }
3931 else if (command->meta == META_ELIF)
3932 {
3933 /* we must evaluate the condition */
3935 }
3936 else if (command->meta == META_ELSE)
3937 {
3938 /* we must execute next command */
3942 st->command++;
3943 }
3944 else if (command->meta == META_ENDIF)
3945 {
3948 if (conditional_active(st->cstack))
3950 /* else state remains CSTATE_SKIP_COMMAND */
3951 st->command++;
3952 }
3953 break;
3954
3955 case IFSTATE_IGNORED:
3956 case IFSTATE_ELSE_FALSE:
3957 if (command->meta == META_IF)
3960 else if (command->meta == META_ENDIF)
3961 {
3964 if (conditional_active(st->cstack))
3966 }
3967 /* could detect "else" & "elif" after "else" */
3968 st->command++;
3969 break;
3970
3971 case IFSTATE_NONE:
3972 case IFSTATE_TRUE:
3973 case IFSTATE_ELSE_TRUE:
3974 default:
3975
3976 /*
3977 * inconsistent if inactive, unreachable dead
3978 * code
3979 */
3980 Assert(false);
3981 }
3982 }
3983 else
3984 {
3985 /* skip and consider next */
3986 st->command++;
3987 }
3988
3989 if (st->state != CSTATE_SKIP_COMMAND)
3990 /* out of quick skip command loop */
3991 break;
3992 }
3993 break;
3994
3995 /*
3996 * Wait for the current SQL command to complete
3997 */
3998 case CSTATE_WAIT_RESULT:
3999 pg_log_debug("client %d receiving", st->id);
4000
4001 /*
4002 * Only check for new network data if we processed all data
4003 * fetched prior. Otherwise we end up doing a syscall for each
4004 * individual pipelined query, which has a measurable
4005 * performance impact.
4006 */
4007 if (PQisBusy(st->con) && !PQconsumeInput(st->con))
4008 {
4009 /* there's something wrong */
4010 commandFailed(st, "SQL", "perhaps the backend died while processing");
4011 st->state = CSTATE_ABORTED;
4012 break;
4013 }
4014 if (PQisBusy(st->con))
4015 return; /* don't have the whole result yet */
4016
4017 /* store or discard the query results */
4018 if (readCommandResponse(st,
4021 {
4022 /*
4023 * outside of pipeline mode: stop reading results.
4024 * pipeline mode: continue reading results until an
4025 * end-of-pipeline response.
4026 */
4029 }
4030 else if (canRetryError(st->estatus))
4031 st->state = CSTATE_ERROR;
4032 else
4033 st->state = CSTATE_ABORTED;
4034 break;
4035
4036 /*
4037 * Wait until sleep is done. This state is entered after a
4038 * \sleep metacommand. The behavior is similar to
4039 * CSTATE_THROTTLE, but proceeds to CSTATE_START_COMMAND
4040 * instead of CSTATE_START_TX.
4041 */
4042 case CSTATE_SLEEP:
4044 if (now < st->sleep_until)
4045 return; /* still sleeping, nothing to do here */
4046 /* Else done sleeping. */
4048 break;
4049
4050 /*
4051 * End of command: record stats and proceed to next command.
4052 */
4053 case CSTATE_END_COMMAND:
4054
4055 /*
4056 * command completed: accumulate per-command execution times
4057 * in thread-local data structure, if per-command latencies
4058 * are requested.
4059 */
4061 {
4063
4064 command = sql_script[st->use_file].commands[st->command];
4065 /* XXX could use a mutex here, but we choose not to */
4066 addToSimpleStats(&command->stats,
4068 }
4069
4070 /* Go ahead with next command, to be executed or skipped */
4071 st->command++;
4072 st->state = conditional_active(st->cstack) ?
4074 break;
4075
4076 /*
4077 * Clean up after an error.
4078 */
4079 case CSTATE_ERROR:
4080 {
4081 TStatus tstatus;
4082
4084
4085 /* Clear the conditional stack */
4087
4088 /* Read and discard until a sync point in pipeline mode */
4090 {
4091 if (!discardUntilSync(st))
4092 {
4093 st->state = CSTATE_ABORTED;
4094 break;
4095 }
4096 }
4097
4098 /*
4099 * Check if we have a (failed) transaction block or not,
4100 * and roll it back if any.
4101 */
4102 tstatus = getTransactionStatus(st->con);
4103 if (tstatus == TSTATUS_IN_BLOCK)
4104 {
4105 /* Try to rollback a (failed) transaction block. */
4106 if (!PQsendQuery(st->con, "ROLLBACK"))
4107 {
4108 pg_log_error("client %d aborted: failed to send sql command for rolling back the failed transaction",
4109 st->id);
4110 st->state = CSTATE_ABORTED;
4111 }
4112 else
4114 }
4115 else if (tstatus == TSTATUS_IDLE)
4116 {
4117 /*
4118 * If time is over, we're done; otherwise, check if we
4119 * can retry the error.
4120 */
4123 }
4124 else
4125 {
4126 if (tstatus == TSTATUS_CONN_ERROR)
4127 pg_log_error("perhaps the backend died while processing");
4128
4129 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4130 st->state = CSTATE_ABORTED;
4131 }
4132 break;
4133 }
4134
4135 /*
4136 * Wait for the rollback command to complete
4137 */
4139 {
4140 PGresult *res;
4141
4142 pg_log_debug("client %d receiving", st->id);
4143 if (!PQconsumeInput(st->con))
4144 {
4145 pg_log_error("client %d aborted while rolling back the transaction after an error; perhaps the backend died while processing",
4146 st->id);
4147 st->state = CSTATE_ABORTED;
4148 break;
4149 }
4150 if (PQisBusy(st->con))
4151 return; /* don't have the whole result yet */
4152
4153 /*
4154 * Read and discard the query result;
4155 */
4156 res = PQgetResult(st->con);
4157 switch (PQresultStatus(res))
4158 {
4159 case PGRES_COMMAND_OK:
4160 /* OK */
4161 PQclear(res);
4162 /* null must be returned */
4163 res = PQgetResult(st->con);
4164 Assert(res == NULL);
4165
4166 /*
4167 * If time is over, we're done; otherwise, check
4168 * if we can retry the error.
4169 */
4172 break;
4173 default:
4174 pg_log_error("client %d aborted while rolling back the transaction after an error; %s",
4175 st->id, PQerrorMessage(st->con));
4176 PQclear(res);
4177 st->state = CSTATE_ABORTED;
4178 break;
4179 }
4180 break;
4181 }
4182
4183 /*
4184 * Retry the transaction after an error.
4185 */
4186 case CSTATE_RETRY:
4187 command = sql_script[st->use_file].commands[st->command];
4188
4189 /*
4190 * Inform that the transaction will be retried after the
4191 * error.
4192 */
4193 if (verbose_errors)
4194 printVerboseErrorMessages(st, &now, true);
4195
4196 /* Count tries and retries */
4197 st->tries++;
4198 command->retries++;
4199
4200 /*
4201 * Reset the random state as they were at the beginning of the
4202 * transaction.
4203 */
4204 st->cs_func_rs = st->random_state;
4205
4206 /* Process the first transaction command. */
4207 st->command = 0;
4210 break;
4211
4212 /*
4213 * Record a failed transaction.
4214 */
4215 case CSTATE_FAILURE:
4216 command = sql_script[st->use_file].commands[st->command];
4217
4218 /* Accumulate the failure. */
4219 command->failures++;
4220
4221 /*
4222 * Inform that the failed transaction will not be retried.
4223 */
4224 if (verbose_errors)
4225 printVerboseErrorMessages(st, &now, false);
4226
4227 /* End the failed transaction. */
4228 st->state = CSTATE_END_TX;
4229 break;
4230
4231 /*
4232 * End of transaction (end of script, really).
4233 */
4234 case CSTATE_END_TX:
4235 {
4236 TStatus tstatus;
4237
4238 /* transaction finished: calculate latency and do log */
4239 processXactStats(thread, st, &now, false, agg);
4240
4241 /*
4242 * missing \endif... cannot happen if CheckConditional was
4243 * okay
4244 */
4246
4247 /*
4248 * We must complete all the transaction blocks that were
4249 * started in this script.
4250 */
4251 tstatus = getTransactionStatus(st->con);
4252 if (tstatus == TSTATUS_IN_BLOCK)
4253 {
4254 pg_log_error("client %d aborted: end of script reached without completing the last transaction",
4255 st->id);
4256 st->state = CSTATE_ABORTED;
4257 break;
4258 }
4259 else if (tstatus != TSTATUS_IDLE)
4260 {
4261 if (tstatus == TSTATUS_CONN_ERROR)
4262 pg_log_error("perhaps the backend died while processing");
4263
4264 pg_log_error("client %d aborted while receiving the transaction status", st->id);
4265 st->state = CSTATE_ABORTED;
4266 break;
4267 }
4268
4269 if (is_connect)
4270 {
4272
4274 finishCon(st);
4275 now = pg_time_now();
4276 thread->conn_duration += now - start;
4277 }
4278
4279 if ((st->cnt >= nxacts && duration <= 0) || timer_exceeded)
4280 {
4281 /* script completed */
4282 st->state = CSTATE_FINISHED;
4283 break;
4284 }
4285
4286 /* next transaction (script) */
4288
4289 /*
4290 * Ensure that we always return on this point, so as to
4291 * avoid an infinite loop if the script only contains meta
4292 * commands.
4293 */
4294 return;
4295 }
4296
4297 /*
4298 * Final states. Close the connection if it's still open.
4299 */
4300 case CSTATE_ABORTED:
4301 case CSTATE_FINISHED:
4302
4303 /*
4304 * Don't measure the disconnection delays here even if in
4305 * CSTATE_FINISHED and -C/--connect option is specified.
4306 * Because in this case all the connections that this thread
4307 * established are closed at the end of transactions and the
4308 * disconnection delays should have already been measured at
4309 * that moment.
4310 *
4311 * In CSTATE_ABORTED state, the measurement is no longer
4312 * necessary because we cannot report complete results anyways
4313 * in this case.
4314 */
4315 finishCon(st);
4316 return;
4317 }
4318 }
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1609
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
PGpipelineStatus PQpipelineStatus(const PGconn *conn)
Definition: fe-connect.c:7723
char * PQerrorMessage(const PGconn *conn)
Definition: fe-connect.c:7679
int PQconsumeInput(PGconn *conn)
Definition: fe-exec.c:1995
int PQsendQuery(PGconn *conn, const char *query)
Definition: fe-exec.c:1427
int PQisBusy(PGconn *conn)
Definition: fe-exec.c:2042
void pg_free(void *ptr)
Definition: fe_memutils.c:105
Assert(PointerIsAligned(start, uint64))
return str start
#define PQgetResult
Definition: libpq-be-fe.h:246
#define PQclear
Definition: libpq-be-fe.h:245
#define PQresultStatus
Definition: libpq-be-fe.h:247
@ PGRES_COMMAND_OK
Definition: libpq-fe.h:125
@ PQ_PIPELINE_OFF
Definition: libpq-fe.h:187
@ PQ_PIPELINE_ON
Definition: libpq-fe.h:188
#define pg_log_debug(...)
Definition: logging.h:133
static pg_time_usec_t pg_time_now(void)
Definition: pgbench.c:877
static void printVerboseErrorMessages(CState *st, pg_time_usec_t *now, bool is_retry)
Definition: pgbench.c:3592
static int64 latency_limit
Definition: pgbench.c:212
static TStatus getTransactionStatus(PGconn *con)
Definition: pgbench.c:3555
static int64 end_time
Definition: pgbench.c:176
static bool doRetry(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:3456
static bool sendCommand(CState *st, Command *command)
Definition: pgbench.c:3183
TStatus
Definition: pgbench.c:470
static void finishCon(CState *st)
Definition: pgbench.c:7769
int64 pg_time_usec_t
Definition: pgbench.c:371
static bool is_connect
Definition: pgbench.c:266
static int nxacts
Definition: pgbench.c:174
static bool report_per_command
Definition: pgbench.c:267
#define PG_TIME_GET_DOUBLE(t)
Definition: pgbench.c:893
static int discardUntilSync(CState *st)
Definition: pgbench.c:3502
static ConnectionStateEnum executeMetaCommand(CState *st, pg_time_usec_t *now)
Definition: pgbench.c:4328
static bool canRetryError(EStatus estatus)
Definition: pgbench.c:3253
static void commandFailed(CState *st, const char *cmd, const char *message)
Definition: pgbench.c:3049
static int chooseScript(TState *thread)
Definition: pgbench.c:3075
#define SQL_COMMAND
Definition: pgbench.c:679
static volatile sig_atomic_t timer_exceeded
Definition: pgbench.c:304
static void processXactStats(TState *thread, CState *st, pg_time_usec_t *now, bool skipped, StatsData *agg)
Definition: pgbench.c:4709
static int duration
Definition: pgbench.c:175
static PGconn * doConnect(void)
Definition: pgbench.c:1557
static void pg_time_now_lazy(pg_time_usec_t *now)
Definition: pgbench.c:887
static bool verbose_errors
Definition: pgbench.c:769
static int64 getPoissonRand(pg_prng_state *state, double center)
Definition: pgbench.c:1205
#define META_COMMAND
Definition: pgbench.c:680
static bool readCommandResponse(CState *st, MetaCommand meta, char *varprefix)
Definition: pgbench.c:3269
int64 cnt
Definition: pgbench.c:638
int id
Definition: pgbench.c:600
pg_time_usec_t txn_scheduled
Definition: pgbench.c:618
pg_time_usec_t stmt_begin
Definition: pgbench.c:621
int command
Definition: pgbench.c:611
int use_file
Definition: pgbench.c:610
ConditionalStack cstack
Definition: pgbench.c:602
pg_prng_state random_state
Definition: pgbench.c:633
pg_time_usec_t txn_begin
Definition: pgbench.c:620
EStatus estatus
Definition: pgbench.c:630
PGconn * con
Definition: pgbench.c:599
pg_prng_state cs_func_rs
Definition: pgbench.c:608
uint32 tries
Definition: pgbench.c:634
bool ** prepared
Definition: pgbench.c:624
ConnectionStateEnum state
Definition: pgbench.c:601
int64 retries
Definition: pgbench.c:753
char * varprefix
Definition: pgbench.c:750
int type
Definition: pgbench.c:745
MetaCommand meta
Definition: pgbench.c:746
SimpleStats stats
Definition: pgbench.c:752
int64 failures
Definition: pgbench.c:754
int64 throttle_trigger
Definition: pgbench.c:662
pg_prng_state ts_throttle_rs
Definition: pgbench.c:659
pg_time_usec_t conn_duration
Definition: pgbench.c:669

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

7936{
7937 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 3097 of file pgbench.c.

3099{
3100 Assert(st->prepared == NULL);
3101
3102 st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
3103 for (int i = 0; i < num_scripts; i++)
3104 {
3105 ParsedScript *script = &sql_script[i];
3106 int numcmds;
3107
3108 for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
3109 ;
3110 st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
3111 }
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
int i
Definition: isn.c:77

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

1964{
1965 char *p,
1966 *name,
1967 *val;
1968
1969 p = sql;
1970 while ((p = strchr(p, ':')) != NULL)
1971 {
1972 int eaten;
1973
1974 name = parseVariable(p, &eaten);
1975 if (name == NULL)
1976 {
1977 while (*p == ':')
1978 {
1979 p++;
1980 }
1981 continue;
1982 }
1983
1984 val = getVariable(variables, name);
1985 free(name);
1986 if (val == NULL)
1987 {
1988 p++;
1989 continue;
1990 }
1991
1992 p = replaceVariable(&sql, p, eaten, val);
1993 }
1994
1995 return sql;
#define free(a)
Definition: header.h:65
static char * parseVariable(const char *sql, int *eaten)
Definition: pgbench.c:1915
static char * getVariable(Variables *variables, char *name)
Definition: pgbench.c:1657
static char * replaceVariable(char **sql, char *param, int len, char *value)
Definition: pgbench.c:1942
const char * name

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3253 of file pgbench.c.

3255{
3256 return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3257 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 5905 of file pgbench.c.

5907{
5908 /* statically check conditional structure */
5910 int i;
5911
5912 for (i = 0; ps->commands[i] != NULL; i++)
5913 {
5914 Command *cmd = ps->commands[i];
5915
5916 if (cmd->type == META_COMMAND)
5917 {
5918 switch (cmd->meta)
5919 {
5920 case META_IF:
5922 break;
5923 case META_ELIF:
5925 ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5927 ConditionError(ps->desc, i + 1, "\\elif after \\else");
5928 break;
5929 case META_ELSE:
5931 ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5933 ConditionError(ps->desc, i + 1, "\\else after \\else");
5935 break;
5936 case META_ENDIF:
5937 if (!conditional_stack_pop(cs))
5938 ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5939 break;
5940 default:
5941 /* ignore anything else... */
5942 break;
5943 }
5944 }
5945 }
5946 if (!conditional_stack_empty(cs))
5947 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:5895

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

5264{
5265 if (initialize_steps[0] == '\0')
5266 pg_fatal("no initialization steps specified");
5267
5268 for (const char *step = initialize_steps; *step != '\0'; step++)
5269 {
5270 if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5271 {
5272 pg_log_error("unrecognized initialization step \"%c\"", *step);
5273 pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5274 exit(1);
5275 }
5276 }
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:164

References ALL_INIT_STEPS, pg_fatal, pg_log_error, and pg_log_error_detail.

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3075 of file pgbench.c.

3077{
3078 int i = 0;
3079 int64 w;
3080
3081 if (num_scripts == 1)
3082 return 0;
3083
3084 w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3085 do
3086 {
3087 w -= sql_script[i++].weight;
3088 } while (w >= 0);
3089
3090 return i - 1;
int64_t int64
Definition: c.h:536
static int64 total_weight
Definition: pgbench.c:767
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1128
int weight
Definition: pgbench.c:760
pg_prng_state ts_choose_rs
Definition: pgbench.c:658

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

7948{
7949 FD_ZERO(&sa->fds);
7950 sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool *  bval 
)
static

Definition at line 2030 of file pgbench.c.

2032{
2033 if (pval->type == PGBT_BOOLEAN)
2034 {
2035 *bval = pval->u.bval;
2036 return true;
2037 }
2038 else /* NULL, INT or DOUBLE */
2039 {
2040 pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2041 *bval = false; /* suppress uninitialized-variable warnings */
2042 return false;
2043 }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:2008
@ 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 2099 of file pgbench.c.

2101{
2102 if (pval->type == PGBT_DOUBLE)
2103 {
2104 *dval = pval->u.dval;
2105 return true;
2106 }
2107 else if (pval->type == PGBT_INT)
2108 {
2109 *dval = (double) pval->u.ival;
2110 return true;
2111 }
2112 else /* BOOLEAN or NULL */
2113 {
2114 pg_log_error("cannot coerce %s to double", valueTypeName(pval));
2115 return false;
2116 }
@ 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 2071 of file pgbench.c.

2073{
2074 if (pval->type == PGBT_INT)
2075 {
2076 *ival = pval->u.ival;
2077 return true;
2078 }
2079 else if (pval->type == PGBT_DOUBLE)
2080 {
2081 double dval = rint(pval->u.dval);
2082
2083 if (isnan(dval) || !FLOAT8_FITS_IN_INT64(dval))
2084 {
2085 pg_log_error("double to int overflow for %f", dval);
2086 return false;
2087 }
2088 *ival = (int64) dval;
2089 return true;
2090 }
2091 else /* BOOLEAN or NULL */
2092 {
2093 pg_log_error("cannot coerce %s to int", valueTypeName(pval));
2094 return false;
2095 }
#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 3059 of file pgbench.c.

3061{
3062 /*
3063 * Errors should only be detected during an SQL command or the
3064 * \endpipeline meta command. Any other case triggers an assertion
3065 * failure.
3066 */
3069
3070 pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3071 st->id, st->command, st->use_file, message);
#define pg_log_info(...)
Definition: logging.h:124

References Assert(), CState::command, ParsedScript::commands, CState::id, Command::meta, META_ENDPIPELINE, 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 3049 of file pgbench.c.

3051{
3052 pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3053 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 1622 of file pgbench.c.

1624{
1625 return strcmp(((const Variable *) v1)->name,
1626 ((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 1227 of file pgbench.c.

1229{
1230 double b = pow(2.0, s - 1.0);
1231 double x,
1232 t,
1233 u,
1234 v;
1235
1236 /* Ensure n is sane */
1237 if (n <= 1)
1238 return 1;
1239
1240 while (true)
1241 {
1242 /* random variates */
1243 u = pg_prng_double(state);
1244 v = pg_prng_double(state);
1245
1246 x = floor(pow(u, -1.0 / (s - 1.0)));
1247
1248 t = pow(1.0 + 1.0 / x, s - 1.0);
1249 /* reject if too large or out of bound */
1250 if (v * x * (t - 1.0) / (b - 1.0) <= t / b && x <= n)
1251 break;
1252 }
1253 return (int64) x;
int b
Definition: isn.c:74
int x
Definition: isn.c:75
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 5895 of file pgbench.c.

5897{
5898 pg_fatal("condition error in script \"%s\" command %d: %s",
5899 desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

static Command * create_sql_command ( PQExpBuffer  buf)
static

Definition at line 5608 of file pgbench.c.

5610{
5611 Command *my_command;
5612 char *p = skip_sql_comments(buf->data);
5613
5614 if (p == NULL)
5615 return NULL;
5616
5617 /* Allocate and initialize Command structure */
5618 my_command = (Command *) pg_malloc(sizeof(Command));
5619 initPQExpBuffer(&my_command->lines);
5620 appendPQExpBufferStr(&my_command->lines, p);
5621 my_command->first_line = NULL; /* this is set later */
5622 my_command->type = SQL_COMMAND;
5623 my_command->meta = META_NONE;
5624 my_command->argc = 0;
5625 my_command->retries = 0;
5626 my_command->failures = 0;
5627 memset(my_command->argv, 0, sizeof(my_command->argv));
5628 my_command->varprefix = NULL; /* allocated later, if needed */
5629 my_command->expr = NULL;
5630 initSimpleStats(&my_command->stats);
5631 my_command->prepname = NULL; /* set later, if needed */
5632
5633 return my_command;
static char * buf
Definition: pg_test_fsync.c:72
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5573
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1420
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:743
PgBenchExpr * expr
Definition: pgbench.c:751
char * argv[MAX_ARGS]
Definition: pgbench.c:748
char * first_line
Definition: pgbench.c:744
int argc
Definition: pgbench.c:747
char * prepname
Definition: pgbench.c:749

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

4784{
4785 PQExpBufferData query;
4786
4787 /* we must have to create some partitions */
4788 Assert(partitions > 0);
4789
4790 fprintf(stderr, "creating %d partitions...\n", partitions);
4791
4792 initPQExpBuffer(&query);
4793
4794 for (int p = 1; p <= partitions; p++)
4795 {
4797 {
4798 int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4799
4800 printfPQExpBuffer(&query,
4801 "create%s table pgbench_accounts_%d\n"
4802 " partition of pgbench_accounts\n"
4803 " for values from (",
4804 unlogged_tables ? " unlogged" : "", p);
4805
4806 /*
4807 * For RANGE, we use open-ended partitions at the beginning and
4808 * end to allow any valid value for the primary key. Although the
4809 * actual minimum and maximum values can be derived from the
4810 * scale, it is more generic and the performance is better.
4811 */
4812 if (p == 1)
4813 appendPQExpBufferStr(&query, "minvalue");
4814 else
4815 appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4816
4817 appendPQExpBufferStr(&query, ") to (");
4818
4819 if (p < partitions)
4820 appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4821 else
4822 appendPQExpBufferStr(&query, "maxvalue");
4823
4824 appendPQExpBufferChar(&query, ')');
4825 }
4826 else if (partition_method == PART_HASH)
4827 printfPQExpBuffer(&query,
4828 "create%s table pgbench_accounts_%d\n"
4829 " partition of pgbench_accounts\n"
4830 " for values with (modulus %d, remainder %d)",
4831 unlogged_tables ? " unlogged" : "", p,
4832 partitions, p - 1);
4833 else /* cannot get there */
4834 Assert(0);
4835
4836 /*
4837 * Per ddlinfo in initCreateTables, fillfactor is needed on table
4838 * pgbench_accounts.
4839 */
4840 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4841
4842 executeStatement(con, query.data);
4843 }
4844
4845 termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:557
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
static int scale
Definition: pgbench.c:182
static int partitions
Definition: pgbench.c:224
static int fillfactor
Definition: pgbench.c:188
static partition_method_t partition_method
Definition: pgbench.c:234
static bool unlogged_tables
Definition: pgbench.c:193
#define naccounts
Definition: pgbench.c:246
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1526
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 3502 of file pgbench.c.

3504{
3505 bool received_sync = false;
3506
3507 /* send a sync */
3508 if (!PQpipelineSync(st->con))
3509 {
3510 pg_log_error("client %d aborted: failed to send a pipeline sync",
3511 st->id);
3512 return 0;
3513 }
3514
3515 /* receive PGRES_PIPELINE_SYNC and null following it */
3516 for (;;)
3517 {
3518 PGresult *res = PQgetResult(st->con);
3519
3521 received_sync = true;
3522 else if (received_sync)
3523 {
3524 /*
3525 * PGRES_PIPELINE_SYNC must be followed by another
3526 * PGRES_PIPELINE_SYNC or NULL; otherwise, assert failure.
3527 */
3528 Assert(res == NULL);
3529
3530 /*
3531 * Reset ongoing sync count to 0 since all PGRES_PIPELINE_SYNC
3532 * results have been discarded.
3533 */
3534 st->num_syncs = 0;
3535 PQclear(res);
3536 break;
3537 }
3538 PQclear(res);
3539 }
3540
3541 /* exit pipeline */
3542 if (PQexitPipelineMode(st->con) != 1)
3543 {
3544 pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3545 st->id);
3546 return 0;
3547 }
3548 return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:3084
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3283
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:139
int num_syncs
Definition: pgbench.c:612

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

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4748 of file pgbench.c.

4750{
4751 int i;
4752
4753 for (i = 0; i < length; i++)
4754 finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn * doConnect ( void  )
static

Definition at line 1557 of file pgbench.c.

1559{
1560 PGconn *conn;
1561 bool new_pass;
1562 static char *password = NULL;
1563
1564 /*
1565 * Start the connection. Loop until we have a password if requested by
1566 * backend.
1567 */
1568 do
1569 {
1570#define PARAMS_ARRAY_SIZE 7
1571
1572 const char *keywords[PARAMS_ARRAY_SIZE];
1573 const char *values[PARAMS_ARRAY_SIZE];
1574
1575 keywords[0] = "host";
1576 values[0] = pghost;
1577 keywords[1] = "port";
1578 values[1] = pgport;
1579 keywords[2] = "user";
1580 values[2] = username;
1581 keywords[3] = "password";
1582 values[3] = password;
1583 keywords[4] = "dbname";
1584 values[4] = dbName;
1585 keywords[5] = "fallback_application_name";
1586 values[5] = progname;
1587 keywords[6] = NULL;
1588 values[6] = NULL;
1589
1590 new_pass = false;
1591
1593
1594 if (!conn)
1595 {
1596 pg_log_error("connection to database \"%s\" failed", dbName);
1597 return NULL;
1598 }
1599
1600 if (PQstatus(conn) == CONNECTION_BAD &&
1602 !password)
1603 {
1604 PQfinish(conn);
1605 password = simple_prompt("Password: ", false);
1606 new_pass = true;
1607 }
1608 } while (new_pass);
1609
1610 /* check to see that the backend connection was successfully made */
1612 {
1614 PQfinish(conn);
1615 return NULL;
1616 }
1617
1618 return conn;
static Datum values[MAXATTR]
Definition: bootstrap.c:153
int PQconnectionNeedsPassword(const PGconn *conn)
Definition: fe-connect.c:7732
ConnStatusType PQstatus(const PGconn *conn)
Definition: fe-connect.c:7616
void PQfinish(PGconn *conn)
Definition: fe-connect.c:5305
PGconn * PQconnectdbParams(const char *const *keywords, const char *const *values, int expand_dbname)
Definition: fe-connect.c:768
static const JsonPathKeyword keywords[]
@ CONNECTION_BAD
Definition: libpq-fe.h:85
#define PARAMS_ARRAY_SIZE
static const char * pghost
Definition: pgbench.c:295
static const char * username
Definition: pgbench.c:297
static const char * progname
Definition: pgbench.c:300
static const char * pgport
Definition: pgbench.c:296
static const char * dbName
Definition: pgbench.c:298
char * simple_prompt(const char *prompt, bool echo)
Definition: sprompt.c:38
static char * password
Definition: streamutil.c:51
PGconn * conn
Definition: streamutil.c:52

References conn, CONNECTION_BAD, dbName, keywords, 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 4589 of file pgbench.c.

4592{
4593 FILE *logfile = thread->logfile;
4595
4596 Assert(use_log);
4597
4598 /*
4599 * Skip the log entry if sampling is enabled and this row doesn't belong
4600 * to the random sample.
4601 */
4602 if (sample_rate != 0.0 &&
4604 return;
4605
4606 /* should we aggregate the results or not? */
4607 if (agg_interval > 0)
4608 {
4610
4611 /*
4612 * Loop until we reach the interval of the current moment, and print
4613 * any empty intervals in between (this may happen with very low tps,
4614 * e.g. --rate=0.1).
4615 */
4616
4617 while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4618 {
4619 double lag_sum = 0.0;
4620 double lag_sum2 = 0.0;
4621 double lag_min = 0.0;
4622 double lag_max = 0.0;
4623 int64 skipped = 0;
4624 int64 serialization_failures = 0;
4625 int64 deadlock_failures = 0;
4626 int64 retried = 0;
4627 int64 retries = 0;
4628
4629 /* print aggregated report to logfile */
4630 fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4631 agg->start_time / 1000000, /* seconds since Unix epoch */
4632 agg->cnt,
4633 agg->latency.sum,
4634 agg->latency.sum2,
4635 agg->latency.min,
4636 agg->latency.max);
4637
4638 if (throttle_delay)
4639 {
4640 lag_sum = agg->lag.sum;
4641 lag_sum2 = agg->lag.sum2;
4642 lag_min = agg->lag.min;
4643 lag_max = agg->lag.max;
4644 }
4645 fprintf(logfile, " %.0f %.0f %.0f %.0f",
4646 lag_sum,
4647 lag_sum2,
4648 lag_min,
4649 lag_max);
4650
4651 if (latency_limit)
4652 skipped = agg->skipped;
4653 fprintf(logfile, " " INT64_FORMAT, skipped);
4654
4655 if (max_tries != 1)
4656 {
4657 retried = agg->retried;
4658 retries = agg->retries;
4659 }
4660 fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4661
4663 {
4664 serialization_failures = agg->serialization_failures;
4665 deadlock_failures = agg->deadlock_failures;
4666 }
4668 serialization_failures,
4669 deadlock_failures);
4670
4671 fputc('\n', logfile);
4672
4673 /* reset data and move to next interval */
4674 initStats(agg, next);
4675 }
4676
4677 /* accumulate the current transaction */
4678 accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4679 }
4680 else
4681 {
4682 /* no, print raw transactions */
4683 if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4684 fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4686 st->id, st->cnt, latency, st->use_file,
4687 now / 1000000, now % 1000000);
4688 else
4689 fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4691 st->id, st->cnt, getResultString(skipped, st->estatus),
4692 st->use_file, now / 1000000, now % 1000000);
4693
4694 if (throttle_delay)
4695 fprintf(logfile, " %.0f", lag);
4696 if (max_tries != 1)
4697 fprintf(logfile, " %u", st->tries - 1);
4698 fputc('\n', logfile);
4699 }
static int32 next
Definition: blutils.c:224
#define INT64CONST(x)
Definition: c.h:553
static FILE * logfile
Definition: pg_regress.c:126
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1477
static uint32 max_tries
Definition: pgbench.c:290
static bool use_log
Definition: pgbench.c:257
static int agg_interval
Definition: pgbench.c:259
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1460
static double sample_rate
Definition: pgbench.c:198
static bool failures_detailed
Definition: pgbench.c:292
static pg_time_usec_t epoch_shift
Definition: pgbench.c:450
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4558
pg_time_usec_t start_time
Definition: pgbench.c:379
FILE * logfile
Definition: pgbench.c:663
pg_prng_state ts_sample_rs
Definition: pgbench.c:660

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, INT64CONST, 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 3456 of file pgbench.c.

3458{
3460
3461 /* We can only retry serialization or deadlock errors. */
3462 if (!canRetryError(st->estatus))
3463 return false;
3464
3465 /*
3466 * We must have at least one option to limit the retrying of transactions
3467 * that got an error.
3468 */
3470
3471 /*
3472 * We cannot retry the error if we have reached the maximum number of
3473 * tries.
3474 */
3475 if (max_tries && st->tries >= max_tries)
3476 return false;
3477
3478 /*
3479 * We cannot retry the error if we spent too much time on this
3480 * transaction.
3481 */
3482 if (latency_limit)
3483 {
3485 if (*now - st->txn_scheduled > latency_limit)
3486 return false;
3487 }
3488
3489 /*
3490 * We cannot retry the error if the benchmark duration is over.
3491 */
3492 if (timer_exceeded)
3493 return false;
3494
3495 /* OK */
3496 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 1799 of file pgbench.c.

1801{
1802 /* total number of variables required now */
1803 needed += variables->nvars;
1804
1805 if (variables->max_vars < needed)
1806 {
1807 variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1808 variables->vars = (Variable *)
1809 pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1810 }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:311
Variable * vars
Definition: pgbench.c:335
int nvars
Definition: pgbench.c:336
int max_vars
Definition: pgbench.c:343

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

2845{
2846 if (isLazyFunc(func))
2847 return evalLazyFunc(st, func, args, retval);
2848 else
2849 return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2151
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2158
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2275

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

2161{
2163 a2;
2164 bool ba1,
2165 ba2;
2166
2167 Assert(isLazyFunc(func) && args != NULL && args->next != NULL);
2168
2169 /* args points to first condition */
2170 if (!evaluateExpr(st, args->expr, &a1))
2171 return false;
2172
2173 /* second condition for AND/OR and corresponding branch for CASE */
2174 args = args->next;
2175
2176 switch (func)
2177 {
2178 case PGBENCH_AND:
2179 if (a1.type == PGBT_NULL)
2180 {
2181 setNullValue(retval);
2182 return true;
2183 }
2184
2185 if (!coerceToBool(&a1, &ba1))
2186 return false;
2187
2188 if (!ba1)
2189 {
2190 setBoolValue(retval, false);
2191 return true;
2192 }
2193
2194 if (!evaluateExpr(st, args->expr, &a2))
2195 return false;
2196
2197 if (a2.type == PGBT_NULL)
2198 {
2199 setNullValue(retval);
2200 return true;
2201 }
2202 else if (!coerceToBool(&a2, &ba2))
2203 return false;
2204 else
2205 {
2206 setBoolValue(retval, ba2);
2207 return true;
2208 }
2209
2210 return true;
2211
2212 case PGBENCH_OR:
2213
2214 if (a1.type == PGBT_NULL)
2215 {
2216 setNullValue(retval);
2217 return true;
2218 }
2219
2220 if (!coerceToBool(&a1, &ba1))
2221 return false;
2222
2223 if (ba1)
2224 {
2225 setBoolValue(retval, true);
2226 return true;
2227 }
2228
2229 if (!evaluateExpr(st, args->expr, &a2))
2230 return false;
2231
2232 if (a2.type == PGBT_NULL)
2233 {
2234 setNullValue(retval);
2235 return true;
2236 }
2237 else if (!coerceToBool(&a2, &ba2))
2238 return false;
2239 else
2240 {
2241 setBoolValue(retval, ba2);
2242 return true;
2243 }
2244
2245 case PGBENCH_CASE:
2246 /* when true, execute branch */
2247 if (valueTruth(&a1))
2248 return evaluateExpr(st, args->expr, retval);
2249
2250 /* now args contains next condition or final else expression */
2251 args = args->next;
2252
2253 /* final else case? */
2254 if (args->next == NULL)
2255 return evaluateExpr(st, args->expr, retval);
2256
2257 /* no, another when, proceed */
2258 return evalLazyFunc(st, PGBENCH_CASE, args, retval);
2259
2260 default:
2261 /* internal error, cannot get here */
2262 Assert(0);
2263 break;
2264 }
2265 return false;
static const FormData_pg_attribute a1
Definition: heap.c:144
static const FormData_pg_attribute a2
Definition: heap.c:157
static void setNullValue(PgBenchValue *pv)
Definition: pgbench.c:2120
static bool evaluateExpr(CState *st, PgBenchExpr *expr, PgBenchValue *retval)
Definition: pgbench.c:2858
static void setBoolValue(PgBenchValue *pv, bool bval)
Definition: pgbench.c:2128
static bool valueTruth(PgBenchValue *pval)
Definition: pgbench.c:2050
static bool coerceToBool(PgBenchValue *pval, bool *bval)
Definition: pgbench.c:2030
@ 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(), evalLazyFunc(), evaluateExpr(), isLazyFunc(), PGBENCH_AND, PGBENCH_CASE, PGBENCH_OR, PGBT_NULL, setBoolValue(), setNullValue(), and valueTruth().

Referenced by evalFunc(), and evalLazyFunc().

◆ evalStandardFunc()

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

Definition at line 2275 of file pgbench.c.

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

2860{
2861 switch (expr->etype)
2862 {
2863 case ENODE_CONSTANT:
2864 {
2865 *retval = expr->u.constant;
2866 return true;
2867 }
2868
2869 case ENODE_VARIABLE:
2870 {
2871 Variable *var;
2872
2873 if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2874 {
2875 pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2876 return false;
2877 }
2878
2879 if (!makeVariableValue(var))
2880 return false;
2881
2882 *retval = var->value;
2883 return true;
2884 }
2885
2886 case ENODE_FUNCTION:
2887 return evalFunc(st,
2888 expr->u.function.function,
2889 expr->u.function.args,
2890 retval);
2891
2892 default:
2893 /* internal error which should never occur */
2894 pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2895 }
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2842
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1690
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1630
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:615
PgBenchValue constant
Definition: pgbench.h:115
char * varname
Definition: pgbench.h:118
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:327

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, CState::variables, and PgBenchExpr::varname.

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

◆ evaluateSleep()

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

Definition at line 3411 of file pgbench.c.

3413{
3414 char *var;
3415 int usec;
3416
3417 if (*argv[1] == ':')
3418 {
3419 if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3420 {
3421 pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3422 return false;
3423 }
3424
3425 usec = atoi(var);
3426
3427 /* Raise an error if the value of a variable is not a number */
3428 if (usec == 0 && !isdigit((unsigned char) *var))
3429 {
3430 pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3431 argv[0], var, argv[1] + 1);
3432 return false;
3433 }
3434 }
3435 else
3436 usec = atoi(argv[1]);
3437
3438 if (argc > 2)
3439 {
3440 if (pg_strcasecmp(argv[2], "ms") == 0)
3441 usec *= 1000;
3442 else if (pg_strcasecmp(argv[2], "s") == 0)
3443 usec *= 1000000;
3444 }
3445 else
3446 usec *= 1000000;
3447
3448 *usecs = usec;
3449 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 4328 of file pgbench.c.

4330{
4331 Command *command = sql_script[st->use_file].commands[st->command];
4332 int argc;
4333 char **argv;
4334
4335 Assert(command != NULL && command->type == META_COMMAND);
4336
4337 argc = command->argc;
4338 argv = command->argv;
4339
4341 {
4343
4345
4346 printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4347 for (int i = 1; i < argc; i++)
4348 appendPQExpBuffer(&buf, " %s", argv[i]);
4349
4350 pg_log_debug("%s", buf.data);
4351
4353 }
4354
4355 if (command->meta == META_SLEEP)
4356 {
4357 int usec;
4358
4359 /*
4360 * A \sleep doesn't execute anything, we just get the delay from the
4361 * argument, and enter the CSTATE_SLEEP state. (The per-command
4362 * latency will be recorded in CSTATE_SLEEP state, not here, after the
4363 * delay has elapsed.)
4364 */
4365 if (!evaluateSleep(&st->variables, argc, argv, &usec))
4366 {
4367 commandFailed(st, "sleep", "execution of meta-command failed");
4368 return CSTATE_ABORTED;
4369 }
4370
4372 st->sleep_until = (*now) + usec;
4373 return CSTATE_SLEEP;
4374 }
4375 else if (command->meta == META_SET)
4376 {
4377 PgBenchExpr *expr = command->expr;
4378 PgBenchValue result;
4379
4380 if (!evaluateExpr(st, expr, &result))
4381 {
4382 commandFailed(st, argv[0], "evaluation of meta-command failed");
4383 return CSTATE_ABORTED;
4384 }
4385
4386 if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4387 {
4388 commandFailed(st, "set", "assignment of meta-command failed");
4389 return CSTATE_ABORTED;
4390 }
4391 }
4392 else if (command->meta == META_IF)
4393 {
4394 /* backslash commands with an expression to evaluate */
4395 PgBenchExpr *expr = command->expr;
4396 PgBenchValue result;
4397 bool cond;
4398
4399 if (!evaluateExpr(st, expr, &result))
4400 {
4401 commandFailed(st, argv[0], "evaluation of meta-command failed");
4402 return CSTATE_ABORTED;
4403 }
4404
4405 cond = valueTruth(&result);
4407 }
4408 else if (command->meta == META_ELIF)
4409 {
4410 /* backslash commands with an expression to evaluate */
4411 PgBenchExpr *expr = command->expr;
4412 PgBenchValue result;
4413 bool cond;
4414
4416 {
4417 /* elif after executed block, skip eval and wait for endif. */
4419 return CSTATE_END_COMMAND;
4420 }
4421
4422 if (!evaluateExpr(st, expr, &result))
4423 {
4424 commandFailed(st, argv[0], "evaluation of meta-command failed");
4425 return CSTATE_ABORTED;
4426 }
4427
4428 cond = valueTruth(&result);
4431 }
4432 else if (command->meta == META_ELSE)
4433 {
4434 switch (conditional_stack_peek(st->cstack))
4435 {
4436 case IFSTATE_TRUE:
4438 break;
4439 case IFSTATE_FALSE: /* inconsistent if active */
4440 case IFSTATE_IGNORED: /* inconsistent if active */
4441 case IFSTATE_NONE: /* else without if */
4442 case IFSTATE_ELSE_TRUE: /* else after else */
4443 case IFSTATE_ELSE_FALSE: /* else after else */
4444 default:
4445 /* dead code if conditional check is ok */
4446 Assert(false);
4447 }
4448 }
4449 else if (command->meta == META_ENDIF)
4450 {
4453 }
4454 else if (command->meta == META_SETSHELL)
4455 {
4456 if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4457 {
4458 commandFailed(st, "setshell", "execution of meta-command failed");
4459 return CSTATE_ABORTED;
4460 }
4461 }
4462 else if (command->meta == META_SHELL)
4463 {
4464 if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4465 {
4466 commandFailed(st, "shell", "execution of meta-command failed");
4467 return CSTATE_ABORTED;
4468 }
4469 }
4470 else if (command->meta == META_STARTPIPELINE)
4471 {
4472 /*
4473 * In pipeline mode, we use a workflow based on libpq pipeline
4474 * functions.
4475 */
4476 if (querymode == QUERY_SIMPLE)
4477 {
4478 commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4479 return CSTATE_ABORTED;
4480 }
4481
4482 /*
4483 * If we're in prepared-query mode, we need to prepare all the
4484 * commands that are inside the pipeline before we actually start the
4485 * pipeline itself. This solves the problem that running BEGIN
4486 * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4487 * snapshot having been acquired by the prepare within the pipeline.
4488 */
4491
4493 {
4494 commandFailed(st, "startpipeline", "already in pipeline mode");
4495 return CSTATE_ABORTED;
4496 }
4497 if (PQenterPipelineMode(st->con) == 0)
4498 {
4499 commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4500 return CSTATE_ABORTED;
4501 }
4502 }
4503 else if (command->meta == META_SYNCPIPELINE)
4504 {
4506 {
4507 commandFailed(st, "syncpipeline", "not in pipeline mode");
4508 return CSTATE_ABORTED;
4509 }
4510 if (PQsendPipelineSync(st->con) == 0)
4511 {
4512 commandFailed(st, "syncpipeline", "failed to send a pipeline sync");
4513 return CSTATE_ABORTED;
4514 }
4515 st->num_syncs++;
4516 }
4517 else if (command->meta == META_ENDPIPELINE)
4518 {
4520 {
4521 commandFailed(st, "endpipeline", "not in pipeline mode");
4522 return CSTATE_ABORTED;
4523 }
4524 if (!PQpipelineSync(st->con))
4525 {
4526 commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4527 return CSTATE_ABORTED;
4528 }
4529 st->num_syncs++;
4530 /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4531 /* collect pending results before getting out of pipeline mode */
4532 return CSTATE_WAIT_RESULT;
4533 }
4534
4535 /*
4536 * executing the expression or shell command might have taken a
4537 * non-negligible amount of time, so reset 'now'
4538 */
4539 *now = 0;
4540
4541 return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:3053
int PQsendPipelineSync(PGconn *conn)
Definition: fe-exec.c:3293
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:714
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3150
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2943
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3411
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1878
pg_time_usec_t sleep_until
Definition: pgbench.c:619

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

1528{
1529 PGresult *res;
1530
1531 res = PQexec(con, sql);
1532 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1533 {
1534 pg_log_error("query failed: %s", PQerrorMessage(con));
1535 pg_log_error_detail("Query was: %s", sql);
1536 exit(1);
1537 }
1538 PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2273

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

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

◆ findBuiltin()

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

Definition at line 6174 of file pgbench.c.

6176{
6177 int i,
6178 found = 0,
6179 len = strlen(name);
6180 const BuiltinScript *result = NULL;
6181
6182 for (i = 0; i < lengthof(builtin_script); i++)
6183 {
6184 if (strncmp(builtin_script[i].name, name, len) == 0)
6185 {
6186 result = &builtin_script[i];
6187 found++;
6188 }
6189 }
6190
6191 /* ok, unambiguous result */
6192 if (found == 1)
6193 return result;
6194
6195 /* error cases */
6196 if (found == 0)
6197 pg_log_error("no builtin script found for name \"%s\"", name);
6198 else /* found > 1 */
6199 pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6200
6202 exit(1);
#define lengthof(array)
Definition: c.h:788
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6162
static const BuiltinScript builtin_script[]
Definition: pgbench.c:781

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

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7769 of file pgbench.c.

7771{
7772 if (st->con != NULL)
7773 {
7774 PQfinish(st->con);
7775 st->con = NULL;
7776 }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5637 of file pgbench.c.

5639{
5640 termPQExpBuffer(&command->lines);
5641 pg_free(command->first_line);
5642 for (int i = 0; i < command->argc; i++)
5643 pg_free(command->argv[i]);
5644 pg_free(command->varprefix);
5645
5646 /*
5647 * It should also free expr recursively, but this is currently not needed
5648 * as only gset commands (which do not have an expression) are freed.
5649 */
5650 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 7940 of file pgbench.c.

7942{
7943 pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ get_table_relkind()

static char get_table_relkind ( PGconn con,
const char *  table 
)
static

Definition at line 852 of file pgbench.c.

854{
855 PGresult *res;
856 char *val;
857 char relkind;
858 const char *params[1] = {table};
859 const char *sql =
860 "SELECT relkind FROM pg_catalog.pg_class WHERE oid=$1::pg_catalog.regclass";
861
862 res = PQexecParams(con, sql, 1, NULL, params, NULL, NULL, 0);
864 {
865 pg_log_error("query failed: %s", PQerrorMessage(con));
866 pg_log_error_detail("Query was: %s", sql);
867 exit(1);
868 }
869 val = PQgetvalue(res, 0, 0);
870 Assert(strlen(val) == 1);
871 relkind = val[0];
872 PQclear(res);
873
874 return relkind;
PGresult * PQexecParams(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:2287
#define PQgetvalue
Definition: libpq-be-fe.h:253
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:128
static const struct lconv_member_info table[]

References Assert(), pg_log_error, pg_log_error_detail, PGRES_TUPLES_OK, PQclear, PQerrorMessage(), PQexecParams(), PQgetvalue, PQresultStatus, table, and val.

Referenced by initPopulateTable().

◆ getExponentialRand()

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

Definition at line 1139 of file pgbench.c.

1142{
1143 double cut,
1144 uniform,
1145 rand;
1146
1147 /* abort if wrong parameter, but must really be checked beforehand */
1148 Assert(parameter > 0.0);
1149 cut = exp(-parameter);
1150 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1151 uniform = 1.0 - pg_prng_double(state);
1152
1153 /*
1154 * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
1155 */
1156 Assert((1.0 - cut) != 0.0);
1157 rand = -log(cut + (1.0 - cut) * uniform) / parameter;
1158 /* return int64 random number within between min and max */
1159 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 4547 of file pgbench.c.

4549{
4550 return (stats->serialization_failures +
4551 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 1163 of file pgbench.c.

1166{
1167 double stdev;
1168 double rand;
1169
1170 /* abort if parameter is too low, but must really be checked beforehand */
1171 Assert(parameter >= MIN_GAUSSIAN_PARAM);
1172
1173 /*
1174 * Get normally-distributed random number in the range -parameter <= stdev
1175 * < parameter.
1176 *
1177 * This loop is executed until the number is in the expected range.
1178 *
1179 * As the minimum parameter is 2.0, the probability of looping is low:
1180 * sqrt(-2 ln(r)) <= 2 => r >= e^{-2} ~ 0.135, then when taking the
1181 * average sinus multiplier as 2/pi, we have a 8.6% looping probability in
1182 * the worst case. For a parameter value of 5.0, the looping probability
1183 * is about e^{-5} * 2 / pi ~ 0.43%.
1184 */
1185 do
1186 {
1188 }
1189 while (stdev < -parameter || stdev >= parameter);
1190
1191 /* stdev is in [-parameter, parameter), normalization to [0,1) */
1192 rand = (stdev + parameter) / (parameter * 2.0);
1193
1194 /* return int64 random number within between min and max */
1195 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 1271 of file pgbench.c.

1273{
1274 int64 result;
1275 int i;
1276
1277 result = FNV_OFFSET_BASIS ^ seed;
1278 for (i = 0; i < 8; ++i)
1279 {
1280 int32 octet = val & 0xff;
1281
1282 val = val >> 8;
1283 result = result ^ octet;
1284 result = result * FNV_PRIME;
1285 }
1286
1287 return result;
int32_t int32
Definition: c.h:535
#define FNV_OFFSET_BASIS
Definition: pgbench.c:85
#define FNV_PRIME
Definition: pgbench.c:84

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1296 of file pgbench.c.

1298{
1299 uint64 result = seed ^ MM2_MUL_TIMES_8; /* sizeof(int64) */
1300 uint64 k = (uint64) val;
1301
1302 k *= MM2_MUL;
1303 k ^= k >> MM2_ROT;
1304 k *= MM2_MUL;
1305
1306 result ^= k;
1307 result *= MM2_MUL;
1308
1309 result ^= result >> MM2_ROT;
1310 result *= MM2_MUL;
1311 result ^= result >> MM2_ROT;
1312
1313 return (int64) result;
uint64_t uint64
Definition: c.h:540
#define MM2_MUL_TIMES_8
Definition: pgbench.c:87
#define MM2_ROT
Definition: pgbench.c:88
#define MM2_MUL
Definition: pgbench.c:86

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

2903{
2904 MetaCommand mc;
2905
2906 if (cmd == NULL)
2907 mc = META_NONE;
2908 else if (pg_strcasecmp(cmd, "set") == 0)
2909 mc = META_SET;
2910 else if (pg_strcasecmp(cmd, "setshell") == 0)
2911 mc = META_SETSHELL;
2912 else if (pg_strcasecmp(cmd, "shell") == 0)
2913 mc = META_SHELL;
2914 else if (pg_strcasecmp(cmd, "sleep") == 0)
2915 mc = META_SLEEP;
2916 else if (pg_strcasecmp(cmd, "if") == 0)
2917 mc = META_IF;
2918 else if (pg_strcasecmp(cmd, "elif") == 0)
2919 mc = META_ELIF;
2920 else if (pg_strcasecmp(cmd, "else") == 0)
2921 mc = META_ELSE;
2922 else if (pg_strcasecmp(cmd, "endif") == 0)
2923 mc = META_ENDIF;
2924 else if (pg_strcasecmp(cmd, "gset") == 0)
2925 mc = META_GSET;
2926 else if (pg_strcasecmp(cmd, "aset") == 0)
2927 mc = META_ASET;
2928 else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2929 mc = META_STARTPIPELINE;
2930 else if (pg_strcasecmp(cmd, "syncpipeline") == 0)
2931 mc = META_SYNCPIPELINE;
2932 else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2933 mc = META_ENDPIPELINE;
2934 else
2935 mc = META_NONE;
2936 return mc;
MetaCommand
Definition: pgbench.c:689

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

1207{
1208 /*
1209 * Use inverse transform sampling to generate a value > 0, such that the
1210 * expected (i.e. average) value is the given argument.
1211 */
1212 double uniform;
1213
1214 /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1215 uniform = 1.0 - pg_prng_double(state);
1216
1217 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 1998 of file pgbench.c.

2001{
2002 int i;
2003
2004 for (i = 0; i < command->argc - 1; i++)
2005 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 1128 of file pgbench.c.

1130{
1131 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 4558 of file pgbench.c.

4560{
4561 if (skipped)
4562 return "skipped";
4563 else if (failures_detailed)
4564 {
4565 switch (estatus)
4566 {
4568 return "serialization";
4570 return "deadlock";
4571 default:
4572 /* internal error which should never occur */
4573 pg_fatal("unexpected error status: %d", estatus);
4574 }
4575 }
4576 else
4577 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 3236 of file pgbench.c.

3238{
3239 if (sqlState != NULL)
3240 {
3241 if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3243 else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3245 }
3246
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:78
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:77

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

5369{
5370 PGresult *res;
5371
5372 /*
5373 * get the scaling factor that should be same as count(*) from
5374 * pgbench_branches if this is not a custom query
5375 */
5376 res = PQexec(con, "select count(*) from pgbench_branches");
5377 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5378 {
5379 char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5380
5381 pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5382
5383 if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5384 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5385 PQdb(con));
5386
5387 exit(1);
5388 }
5389 scale = atoi(PQgetvalue(res, 0, 0));
5390 if (scale < 0)
5391 pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5392 PQgetvalue(res, 0, 0));
5393 PQclear(res);
5394
5395 /* warn if we override user-given -s switch */
5396 if (scale_given)
5397 pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5398 scale);
5399
5400 /*
5401 * Get the partition information for the first "pgbench_accounts" table
5402 * found in search_path.
5403 *
5404 * The result is empty if no "pgbench_accounts" is found.
5405 *
5406 * Otherwise, it always returns one row even if the table is not
5407 * partitioned (in which case the partition strategy is NULL).
5408 *
5409 * The number of partitions can be 0 even for partitioned tables, if no
5410 * partition is attached.
5411 *
5412 * We assume no partitioning on any failure, so as to avoid failing on an
5413 * old version without "pg_partitioned_table".
5414 */
5415 res = PQexec(con,
5416 "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5417 "from pg_catalog.pg_class as c "
5418 "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5419 "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5420 "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5421 "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5422 "where c.relname = 'pgbench_accounts' and o.n is not null "
5423 "group by 1, 2 "
5424 "order by 1 asc "
5425 "limit 1");
5426
5427 if (PQresultStatus(res) != PGRES_TUPLES_OK)
5428 {
5429 /* probably an older version, coldly assume no partitioning */
5431 partitions = 0;
5432 }
5433 else if (PQntuples(res) == 0)
5434 {
5435 /*
5436 * This case is unlikely as pgbench already found "pgbench_branches"
5437 * above to compute the scale.
5438 */
5439 pg_log_error("no pgbench_accounts table found in \"search_path\"");
5440 pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5441 exit(1);
5442 }
5443 else /* PQntuples(res) == 1 */
5444 {
5445 /* normal case, extract partition information */
5446 if (PQgetisnull(res, 0, 1))
5448 else
5449 {
5450 char *ps = PQgetvalue(res, 0, 1);
5451
5452 /* column must be there */
5453 Assert(ps != NULL);
5454
5455 if (strcmp(ps, "r") == 0)
5457 else if (strcmp(ps, "h") == 0)
5459 else
5460 {
5461 /* possibly a newer version with new partition method */
5462 pg_fatal("unexpected partition method: \"%s\"", ps);
5463 }
5464 }
5465
5466 partitions = atoi(PQgetvalue(res, 0, 2));
5467 }
5468
5469 PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:7513
#define PQresultErrorField
Definition: libpq-be-fe.h:249
#define PQgetisnull
Definition: libpq-be-fe.h:255
#define PQntuples
Definition: libpq-be-fe.h:251
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:57

References Assert(), ERRCODE_UNDEFINED_TABLE, 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, and scale.

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3555 of file pgbench.c.

3557{
3558 PGTransactionStatusType tx_status;
3559
3560 tx_status = PQtransactionStatus(con);
3561 switch (tx_status)
3562 {
3563 case PQTRANS_IDLE:
3564 return TSTATUS_IDLE;
3565 case PQTRANS_INTRANS:
3566 case PQTRANS_INERROR:
3567 return TSTATUS_IN_BLOCK;
3568 case PQTRANS_UNKNOWN:
3569 /* PQTRANS_UNKNOWN is expected given a broken connection */
3570 if (PQstatus(con) == CONNECTION_BAD)
3571 return TSTATUS_CONN_ERROR;
3572 /* fall through */
3573 case PQTRANS_ACTIVE:
3574 default:
3575
3576 /*
3577 * We cannot find out whether we are in a transaction block or
3578 * not. Internal error which should never occur.
3579 */
3580 pg_log_error("unexpected transaction status %d", tx_status);
3581 return TSTATUS_OTHER_ERROR;
3582 }
3583
3584 /* not reached */
3585 Assert(false);
3586 return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:7624
PGTransactionStatusType
Definition: libpq-fe.h:146
@ PQTRANS_INTRANS
Definition: libpq-fe.h:149
@ PQTRANS_IDLE
Definition: libpq-fe.h:147
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:148
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:151
@ PQTRANS_INERROR
Definition: libpq-fe.h:150

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

1659{
1660 Variable *var;
1661 char stringform[64];
1662
1663 var = lookupVariable(variables, name);
1664 if (var == NULL)
1665 return NULL; /* not found */
1666
1667 if (var->svalue)
1668 return var->svalue; /* we have it in string form */
1669
1670 /* We need to produce a string equivalent of the value */
1671 Assert(var->value.type != PGBT_NO_VALUE);
1672 if (var->value.type == PGBT_NULL)
1673 snprintf(stringform, sizeof(stringform), "NULL");
1674 else if (var->value.type == PGBT_BOOLEAN)
1675 snprintf(stringform, sizeof(stringform),
1676 "%s", var->value.u.bval ? "true" : "false");
1677 else if (var->value.type == PGBT_INT)
1678 snprintf(stringform, sizeof(stringform),
1679 INT64_FORMAT, var->value.u.ival);
1680 else if (var->value.type == PGBT_DOUBLE)
1681 snprintf(stringform, sizeof(stringform),
1682 "%.*g", DBL_DIG, var->value.u.dval);
1683 else /* internal error, unexpected type */
1684 Assert(0);
1685 var->svalue = pg_strdup(stringform);
1686 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:239
char * svalue
Definition: pgbench.c:326

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

1259{
1260 int64 n = max - min + 1;
1261
1262 /* abort if parameter is invalid */
1264
1265 return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1227

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

7787{
7788 timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4974 of file pgbench.c.

4976{
4977 /* "filler" column defaults to blank padded empty string */
4979 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4980 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 4956 of file pgbench.c.

4958{
4959 /* "filler" column uses NULL */
4961 INT64_FORMAT "\t0\t\\N\n",
4962 curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5236 of file pgbench.c.

5238{
5239 static const char *const DDLKEYs[] = {
5240 "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5241 "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5242 "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5243 "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5244 "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5245 };
5246 int i;
5247
5248 fprintf(stderr, "creating foreign keys...\n");
5249 for (i = 0; i < lengthof(DDLKEYs); i++)
5250 {
5251 executeStatement(con, DDLKEYs[i]);
5252 }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5198 of file pgbench.c.

5200{
5201 static const char *const DDLINDEXes[] = {
5202 "alter table pgbench_branches add primary key (bid)",
5203 "alter table pgbench_tellers add primary key (tid)",
5204 "alter table pgbench_accounts add primary key (aid)"
5205 };
5206 int i;
5207 PQExpBufferData query;
5208
5209 fprintf(stderr, "creating primary keys...\n");
5210 initPQExpBuffer(&query);
5211
5212 for (i = 0; i < lengthof(DDLINDEXes); i++)
5213 {
5214 resetPQExpBuffer(&query);
5215 appendPQExpBufferStr(&query, DDLINDEXes[i]);
5216
5217 if (index_tablespace != NULL)
5218 {
5219 char *escape_tablespace;
5220
5221 escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5222 strlen(index_tablespace));
5223 appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5224 PQfreemem(escape_tablespace);
5225 }
5226
5227 executeStatement(con, query.data);
5228 }
5229
5230 termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4043
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4382
static char * index_tablespace
Definition: pgbench.c:218
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 4851 of file pgbench.c.

4853{
4854 /*
4855 * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4856 * fields in these table declarations were intended to comply with that.
4857 * The pgbench_accounts table complies with that because the "filler"
4858 * column is set to blank-padded empty string. But for all other tables
4859 * the columns default to NULL and so don't actually take any space. We
4860 * could fix that by giving them non-null default values. However, that
4861 * would completely break comparability of pgbench results with prior
4862 * versions. Since pgbench has never pretended to be fully TPC-B compliant
4863 * anyway, we stick with the historical behavior.
4864 */
4865 struct ddlinfo
4866 {
4867 const char *table; /* table name */
4868 const char *smcols; /* column decls if accountIDs are 32 bits */
4869 const char *bigcols; /* column decls if accountIDs are 64 bits */
4870 int declare_fillfactor;
4871 };
4872 static const struct ddlinfo DDLs[] = {
4873 {
4874 "pgbench_history",
4875 "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4876 "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4877 0
4878 },
4879 {
4880 "pgbench_tellers",
4881 "tid int not null,bid int,tbalance int,filler char(84)",
4882 "tid int not null,bid int,tbalance int,filler char(84)",
4883 1
4884 },
4885 {
4886 "pgbench_accounts",
4887 "aid int not null,bid int,abalance int,filler char(84)",
4888 "aid bigint not null,bid int,abalance int,filler char(84)",
4889 1
4890 },
4891 {
4892 "pgbench_branches",
4893 "bid int not null,bbalance int,filler char(88)",
4894 "bid int not null,bbalance int,filler char(88)",
4895 1
4896 }
4897 };
4898 int i;
4899 PQExpBufferData query;
4900
4901 fprintf(stderr, "creating tables...\n");
4902
4903 initPQExpBuffer(&query);
4904
4905 for (i = 0; i < lengthof(DDLs); i++)
4906 {
4907 const struct ddlinfo *ddl = &DDLs[i];
4908
4909 /* Construct new create table statement. */
4910 printfPQExpBuffer(&query, "create%s table %s(%s)",
4911 (unlogged_tables && partition_method == PART_NONE) ? " unlogged" : "",
4912 ddl->table,
4913 (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4914
4915 /* Partition pgbench_accounts table */
4916 if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4917 appendPQExpBuffer(&query,
4918 " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4919 else if (ddl->declare_fillfactor)
4920 {
4921 /* fillfactor is only expected on actual tables */
4922 appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4923 }
4924
4925 if (tablespace != NULL)
4926 {
4927 char *escape_tablespace;
4928
4929 escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4930 appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4931 PQfreemem(escape_tablespace);
4932 }
4933
4934 executeStatement(con, query.data);
4935 }
4936
4937 termPQExpBuffer(&query);
4938
4940 createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4782
static const char *const PARTITION_METHOD[]
Definition: pgbench.c:235
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:255
static char * tablespace
Definition: pgbench.c:217

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

Referenced by runInitSteps().

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4760 of file pgbench.c.

4762{
4763 fprintf(stderr, "dropping old tables...\n");
4764
4765 /*
4766 * We drop all the tables in one command, so that whether there are
4767 * foreign key dependencies or not doesn't matter.
4768 */
4769 executeStatement(con, "drop table if exists "
4770 "pgbench_accounts, "
4771 "pgbench_branches, "
4772 "pgbench_history, "
4773 "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5108 of file pgbench.c.

5110{
5111 fprintf(stderr, "generating data (client-side)...\n");
5112
5113 /*
5114 * we do all of this in one transaction to enable the backend's
5115 * data-loading optimizations
5116 */
5117 executeStatement(con, "begin");
5118
5119 /* truncate away any old data */
5120 initTruncateTables(con);
5121
5122 /*
5123 * fill branches, tellers, accounts in that order in case foreign keys
5124 * already exist
5125 */
5126 initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5127 initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5128 initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5129
5130 executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4965
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4956
#define ntellers
Definition: pgbench.c:245
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4946
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4974
#define nbranches
Definition: pgbench.c:244
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4983

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

5142{
5143 PQExpBufferData sql;
5144
5145 fprintf(stderr, "generating data (server-side)...\n");
5146
5147 /*
5148 * we do all of this in one transaction to enable the backend's
5149 * data-loading optimizations
5150 */
5151 executeStatement(con, "begin");
5152
5153 /* truncate away any old data */
5154 initTruncateTables(con);
5155
5156 initPQExpBuffer(&sql);
5157
5158 printfPQExpBuffer(&sql,
5159 "insert into pgbench_branches(bid,bbalance) "
5160 "select bid, 0 "
5161 "from generate_series(1, %d) as bid", nbranches * scale);
5162 executeStatement(con, sql.data);
5163
5164 printfPQExpBuffer(&sql,
5165 "insert into pgbench_tellers(tid,bid,tbalance) "
5166 "select tid, (tid - 1) / %d + 1, 0 "
5167 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5168 executeStatement(con, sql.data);
5169
5170 printfPQExpBuffer(&sql,
5171 "insert into pgbench_accounts(aid,bid,abalance,filler) "
5172 "select aid, (aid - 1) / %d + 1, 0, '' "
5173 "from generate_series(1, " INT64_FORMAT ") as aid",
5175 executeStatement(con, sql.data);
5176
5177 termPQExpBuffer(&sql);
5178
5179 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 4983 of file pgbench.c.

4986{
4987 int n;
4988 int64 k;
4989 int chars = 0;
4990 int prev_chars = 0;
4991 PGresult *res;
4992 PQExpBufferData sql;
4993 char copy_statement[256];
4994 const char *copy_statement_fmt = "copy %s from stdin";
4995 int64 total = base * scale;
4996
4997 /* used to track elapsed time and estimate of the remaining time */
4999 int log_interval = 1;
5000
5001 /* Stay on the same line if reporting to a terminal */
5002 char eol = isatty(fileno(stderr)) ? '\r' : '\n';
5003
5004 initPQExpBuffer(&sql);
5005
5006 /* Use COPY with FREEZE on v14 and later for all ordinary tables */
5007 if ((PQserverVersion(con) >= 140000) &&
5008 get_table_relkind(con, table) == RELKIND_RELATION)
5009 copy_statement_fmt = "copy %s from stdin with (freeze on)";
5010
5011
5012 n = pg_snprintf(copy_statement, sizeof(copy_statement), copy_statement_fmt, table);
5013 if (n >= sizeof(copy_statement))
5014 pg_fatal("invalid buffer size: must be at least %d characters long", n);
5015 else if (n == -1)
5016 pg_fatal("invalid format string");
5017
5018 res = PQexec(con, copy_statement);
5019
5020 if (PQresultStatus(res) != PGRES_COPY_IN)
5021 pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
5022 PQclear(res);
5023
5024 start = pg_time_now();
5025
5026 for (k = 0; k < total; k++)
5027 {
5028 int64 j = k + 1;
5029
5030 init_row(&sql, k);
5031 if (PQputline(con, sql.data))
5032 pg_fatal("PQputline failed");
5033
5034 if (CancelRequested)
5035 break;
5036
5037 /*
5038 * If we want to stick with the original logging, print a message each
5039 * 100k inserted rows.
5040 */
5041 if ((!use_quiet) && (j % 100000 == 0))
5042 {
5043 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5044 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5045
5046 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5047 j, total,
5048 (int) ((j * 100) / total),
5049 table, elapsed_sec, remaining_sec);
5050
5051 /*
5052 * If the previous progress message is longer than the current
5053 * one, add spaces to the current line to fully overwrite any
5054 * remaining characters from the previous message.
5055 */
5056 if (prev_chars > chars)
5057 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5058 fputc(eol, stderr);
5059 prev_chars = chars;
5060 }
5061 /* let's not call the timing for each row, but only each 100 rows */
5062 else if (use_quiet && (j % 100 == 0))
5063 {
5064 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5065 double remaining_sec = ((double) total - j) * elapsed_sec / j;
5066
5067 /* have we reached the next interval (or end)? */
5068 if ((j == total) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
5069 {
5070 chars = fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)",
5071 j, total,
5072 (int) ((j * 100) / total),
5073 table, elapsed_sec, remaining_sec);
5074
5075 /*
5076 * If the previous progress message is longer than the current
5077 * one, add spaces to the current line to fully overwrite any
5078 * remaining characters from the previous message.
5079 */
5080 if (prev_chars > chars)
5081 fprintf(stderr, "%*c", prev_chars - chars, ' ');
5082 fputc(eol, stderr);
5083 prev_chars = chars;
5084
5085 /* skip to the next interval */
5086 log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
5087 }
5088 }
5089 }
5090
5091 if (chars != 0 && eol != '\n')
5092 fprintf(stderr, "%*c\r", chars, ' '); /* Clear the current line */
5093
5094 if (PQputline(con, "\\.\n"))
5095 pg_fatal("very last PQputline failed");
5096 if (PQendcopy(con))
5097 pg_fatal("PQendcopy failed");
5098
5099 termPQExpBuffer(&sql);
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:7669
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2960
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2929
int j
Definition: isn.c:78
@ PGRES_COPY_IN
Definition: libpq-fe.h:132
static char get_table_relkind(PGconn *con, const char *table)
Definition: pgbench.c:852
#define LOG_STEP_SECONDS
Definition: pgbench.c:166
static bool use_quiet
Definition: pgbench.c:258
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, get_table_relkind(), initPQExpBuffer(), INT64_FORMAT, j, LOG_STEP_SECONDS, pg_fatal, pg_snprintf(), PG_TIME_GET_DOUBLE, pg_time_now(), PGRES_COPY_IN, PQclear, PQendcopy(), PQerrorMessage(), PQexec(), PQputline(), PQresultStatus, PQserverVersion(), scale, start, table, termPQExpBuffer(), and use_quiet.

Referenced by initGenerateDataClientSide().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 1114 of file pgbench.c.

1116{
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:478

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

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1420 of file pgbench.c.

1422{
1423 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 4965 of file pgbench.c.

4967{
4968 /* "filler" column uses NULL */
4970 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n",
4971 curr + 1, curr / ntellers + 1);

References INT64_FORMAT, ntellers, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initTruncateTables()

static void initTruncateTables ( PGconn con)
static

Definition at line 4946 of file pgbench.c.

4948{
4949 executeStatement(con, "truncate table "
4950 "pgbench_accounts, "
4951 "pgbench_branches, "
4952 "pgbench_history, "
4953 "pgbench_tellers");

References executeStatement().

Referenced by initGenerateDataClientSide(), and initGenerateDataServerSide().

◆ initVacuum()

static void initVacuum ( PGconn con)
static

Definition at line 5185 of file pgbench.c.

5187{
5188 fprintf(stderr, "vacuuming...\n");
5189 executeStatement(con, "vacuum analyze pgbench_branches");
5190 executeStatement(con, "vacuum analyze pgbench_tellers");
5191 executeStatement(con, "vacuum analyze pgbench_accounts");
5192 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 977 of file pgbench.c.

979{
980 const char *ptr = str;
981
982 /* skip leading spaces; cast is consistent with strtoint64 */
983 while (*ptr && isspace((unsigned char) *ptr))
984 ptr++;
985
986 /* skip sign */
987 if (*ptr == '+' || *ptr == '-')
988 ptr++;
989
990 /* at least one digit */
991 if (*ptr && !isdigit((unsigned char) *ptr))
992 return false;
993
994 /* eat all digits */
995 while (*ptr && isdigit((unsigned char) *ptr))
996 ptr++;
997
998 /* must have reached end of string */
999 return *ptr == '\0';
const char * str

References str.

Referenced by makeVariableValue().

◆ isLazyFunc()

static bool isLazyFunc ( PgBenchFunction  func)
static

Definition at line 2151 of file pgbench.c.

2153{
2154 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 6162 of file pgbench.c.

6164{
6165 int i;
6166
6167 fprintf(stderr, "Available builtin scripts:\n");
6168 for (i = 0; i < lengthof(builtin_script); i++)
6169 fprintf(stderr, " %13s: %s\n", builtin_script[i].name, builtin_script[i].desc);
6170 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 1818 of file pgbench.c.

1820{
1821 Variable *var;
1822
1823 var = lookupVariable(variables, name);
1824 if (var == NULL)
1825 {
1826 /*
1827 * Check for the name only when declaring a new variable to avoid
1828 * overhead.
1829 */
1831 {
1832 pg_log_error("%s: invalid variable name: \"%s\"", context, name);
1833 return NULL;
1834 }
1835
1836 /* Create variable at the end of the array */
1837 enlargeVariables(variables, 1);
1838
1839 var = &(variables->vars[variables->nvars]);
1840
1841 var->name = pg_strdup(name);
1842 var->svalue = NULL;
1843 /* caller is expected to initialize remaining fields */
1844
1845 variables->nvars++;
1846 /* we don't re-sort the array till we have to */
1847 variables->vars_sorted = false;
1848 }
1849
1850 return var;
static bool valid_variable_name(const char *name)
Definition: pgbench.c:1764
static void enlargeVariables(Variables *variables, int needed)
Definition: pgbench.c:1799
char * name
Definition: pgbench.c:325
bool vars_sorted
Definition: pgbench.c:345

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

1632{
1633 Variable key;
1634
1635 /* On some versions of Solaris, bsearch of zero items dumps core */
1636 if (variables->nvars <= 0)
1637 return NULL;
1638
1639 /* Sort if we have to */
1640 if (!variables->vars_sorted)
1641 {
1642 qsort(variables->vars, variables->nvars, sizeof(Variable),
1644 variables->vars_sorted = true;
1645 }
1646
1647 /* Now we can search */
1648 key.name = name;
1649 return (Variable *) bsearch(&key,
1650 variables->vars,
1651 variables->nvars,
1652 sizeof(Variable),
static int compareVariableNames(const void *v1, const void *v2)
Definition: pgbench.c:1622
#define qsort(a, b, c, d)
Definition: port.h:479

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

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

1692{
1693 size_t slen;
1694
1695 if (var->value.type != PGBT_NO_VALUE)
1696 return true; /* no work */
1697
1698 slen = strlen(var->svalue);
1699
1700 if (slen == 0)
1701 /* what should it do on ""? */
1702 return false;
1703
1704 if (pg_strcasecmp(var->svalue, "null") == 0)
1705 {
1706 setNullValue(&var->value);
1707 }
1708
1709 /*
1710 * accept prefixes such as y, ye, n, no... but not for "o". 0/1 are
1711 * recognized later as an int, which is converted to bool if needed.
1712 */
1713 else if (pg_strncasecmp(var->svalue, "true", slen) == 0 ||
1714 pg_strncasecmp(var->svalue, "yes", slen) == 0 ||
1715 pg_strcasecmp(var->svalue, "on") == 0)
1716 {
1717 setBoolValue(&var->value, true);
1718 }
1719 else if (pg_strncasecmp(var->svalue, "false", slen) == 0 ||
1720 pg_strncasecmp(var->svalue, "no", slen) == 0 ||
1721 pg_strcasecmp(var->svalue, "off") == 0 ||
1722 pg_strcasecmp(var->svalue, "of") == 0)
1723 {
1724 setBoolValue(&var->value, false);
1725 }
1726 else if (is_an_int(var->svalue))
1727 {
1728 /* if it looks like an int, it must be an int without overflow */
1729 int64 iv;
1730
1731 if (!strtoint64(var->svalue, false, &iv))
1732 return false;
1733
1734 setIntValue(&var->value, iv);
1735 }
1736 else /* type should be double */
1737 {
1738 double dv;
1739
1740 if (!strtodouble(var->svalue, true, &dv))
1741 {
1742 pg_log_error("malformed variable \"%s\" value: \"%s\"",
1743 var->name, var->svalue);
1744 return false;
1745 }
1746 setDoubleValue(&var->value, dv);
1747 }
1748 return true;
bool strtodouble(const char *str, bool errorOK, double *dv)
Definition: pgbench.c:1085
bool strtoint64(const char *str, bool errorOK, int64 *result)
Definition: pgbench.c:1014
static bool is_an_int(const char *str)
Definition: pgbench.c:977
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 1444 of file pgbench.c.

1446{
1447 if (acc->count == 0 || ss->min < acc->min)
1448 acc->min = ss->min;
1449 if (acc->count == 0 || ss->max > acc->max)
1450 acc->max = ss->max;
1451 acc->count += ss->count;
1452 acc->sum += ss->sum;
1453 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 5476 of file pgbench.c.

5478{
5479 char *sql,
5480 *p;
5481
5482 cmd->argc = 1;
5483
5484 p = sql = pg_strdup(cmd->lines.data);
5485 while ((p = strchr(p, ':')) != NULL)
5486 {
5487 char var[13];
5488 char *name;
5489 int eaten;
5490
5491 name = parseVariable(p, &eaten);
5492 if (name == NULL)
5493 {
5494 while (*p == ':')
5495 {
5496 p++;
5497 }
5498 continue;
5499 }
5500
5501 /*
5502 * cmd->argv[0] is the SQL statement itself, so the max number of
5503 * arguments is one less than MAX_ARGS
5504 */
5505 if (cmd->argc >= MAX_ARGS)
5506 {
5507 pg_log_error("statement has too many arguments (maximum is %d): %s",
5508 MAX_ARGS - 1, cmd->lines.data);
5509 pg_free(name);
5510 return false;
5511 }
5512
5513 sprintf(var, "$%d", cmd->argc);
5514 p = replaceVariable(&sql, p, eaten, var);
5515
5516 cmd->argv[cmd->argc] = name;
5517 cmd->argc++;
5518 }
5519
5520 Assert(cmd->argv[0] == NULL);
5521 cmd->argv[0] = sql;
5522 return true;
#define MAX_ARGS
Definition: pgbench.c:686
#define sprintf
Definition: port.h:241

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

5957{
5959 PsqlScanState sstate;
5960 PQExpBufferData line_buf;
5961 int alloc_num;
5962 int index;
5963
5964#define COMMANDS_ALLOC_NUM 128
5965 alloc_num = COMMANDS_ALLOC_NUM;
5966
5967 /* Initialize all fields of ps */
5968 ps.desc = desc;
5969 ps.weight = weight;
5970 ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
5971 initStats(&ps.stats, 0);
5972
5973 /* Prepare to parse script */
5975
5976 /*
5977 * Ideally, we'd scan scripts using the encoding and stdstrings settings
5978 * we get from a DB connection. However, without major rearrangement of
5979 * pgbench's argument parsing, we can't have a DB connection at the time
5980 * we parse scripts. Using SQL_ASCII (encoding 0) should work well enough
5981 * with any backend-safe encoding, though conceivably we could be fooled
5982 * if a script file uses a client-only encoding. We also assume that
5983 * stdstrings should be true, which is a bit riskier.
5984 */
5985 psql_scan_setup(sstate, script, strlen(script), 0, true);
5986
5987 initPQExpBuffer(&line_buf);
5988
5989 index = 0;
5990
5991 for (;;)
5992 {
5993 PsqlScanResult sr;
5994 promptStatus_t prompt;
5995 Command *command = NULL;
5996
5997 resetPQExpBuffer(&line_buf);
5998
5999 sr = psql_scan(sstate, &line_buf, &prompt);
6000
6001 /* If we collected a new SQL command, process that */
6002 command = create_sql_command(&line_buf);
6003
6004 /* store new command */
6005 if (command)
6006 ps.commands[index++] = command;
6007
6008 /* If we reached a backslash, process that */
6009 if (sr == PSCAN_BACKSLASH)
6010 {
6011 int lineno;
6012 int start_offset;
6013
6014 /* Capture location of the backslash */
6015 psql_scan_get_location(sstate, &lineno, &start_offset);
6016 start_offset--;
6017
6018 command = process_backslash_command(sstate, desc,
6019 lineno, start_offset);
6020
6021 if (command)
6022 {
6023 /*
6024 * If this is gset or aset, merge into the preceding command.
6025 * (We don't use a command slot in this case).
6026 */
6027 if (command->meta == META_GSET || command->meta == META_ASET)
6028 {
6029 Command *cmd;
6030
6031 if (index == 0)
6032 syntax_error(desc, lineno, NULL, NULL,
6033 "\\gset must follow an SQL command",
6034 NULL, -1);
6035
6036 cmd = ps.commands[index - 1];
6037
6038 if (cmd->type != SQL_COMMAND ||
6039 cmd->varprefix != NULL)
6040 syntax_error(desc, lineno, NULL, NULL,
6041 "\\gset must follow an SQL command",
6042 cmd->first_line, -1);
6043
6044 /* get variable prefix */
6045 if (command->argc <= 1 || command->argv[1][0] == '\0')
6046 cmd->varprefix = pg_strdup("");
6047 else
6048 cmd->varprefix = pg_strdup(command->argv[1]);
6049
6050 /* update the sql command meta */
6051 cmd->meta = command->meta;
6052
6053 /* cleanup unused command */
6054 free_command(command);
6055
6056 continue;
6057 }
6058
6059 /* Attach any other backslash command as a new command */
6060 ps.commands[index++] = command;
6061 }
6062 }
6063
6064 /*
6065 * Since we used a command slot, allocate more if needed. Note we
6066 * always allocate one more in order to accommodate the NULL
6067 * terminator below.
6068 */
6069 if (index >= alloc_num)
6070 {
6071 alloc_num += COMMANDS_ALLOC_NUM;
6072 ps.commands = (Command **)
6073 pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
6074 }
6075
6076 /* Done if we reached EOF */
6077 if (sr == PSCAN_INCOMPLETE || sr == PSCAN_EOL)
6078 break;
6079 }
6080
6081 ps.commands[index] = NULL;
6082
6083 addScript(&ps);
6084
6085 termPQExpBuffer(&line_buf);
6086 psql_scan_finish(sstate);
6087 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:5537
#define COMMANDS_ALLOC_NUM
static void free_command(Command *command)
Definition: pgbench.c:5637
static Command * create_sql_command(PQExpBuffer buf)
Definition: pgbench.c:5608
static Command * process_backslash_command(PsqlScanState sstate, const char *source, int lineno, int start_offset)
Definition: pgbench.c:5694
static void addScript(const ParsedScript *script)
Definition: pgbench.c:6247
static const PsqlScanCallbacks pgbench_callbacks
Definition: pgbench.c:847
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_get_location(PsqlScanState state, int *lineno, int *offset)
Definition: psqlscan.l:1335
void psql_scan_destroy(PsqlScanState state)
Definition: psqlscan.l:1022
PsqlScanResult psql_scan(PsqlScanState state, PQExpBuffer query_buf, promptStatus_t *prompt)
Definition: psqlscan.l:1121
PsqlScanState psql_scan_create(const PsqlScanCallbacks *callbacks)
Definition: psqlscan.l:1001
void psql_scan_setup(PsqlScanState state, const char *line, int line_len, int encoding, bool std_strings)
Definition: psqlscan.l:1059
void psql_scan_finish(PsqlScanState state)
Definition: psqlscan.l:1248
Definition: type.h:96

References addScript(), Command::argc, Command::argv, COMMANDS_ALLOC_NUM, create_sql_command(), 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_get_location(), 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 6210 of file pgbench.c.

6212{
6213 char *sep;
6214 int weight;
6215
6216 if ((sep = strrchr(option, WSEP)))
6217 {
6218 int namelen = sep - option;
6219 long wtmp;
6220 char *badp;
6221
6222 /* generate the script name */
6223 *script = pg_malloc(namelen + 1);
6224 strncpy(*script, option, namelen);
6225 (*script)[namelen] = '\0';
6226
6227 /* process digits of the weight spec */
6228 errno = 0;
6229 wtmp = strtol(sep + 1, &badp, 10);
6230 if (errno != 0 || badp == sep + 1 || *badp != '\0')
6231 pg_fatal("invalid weight specification: %s", sep);
6232 if (wtmp > INT_MAX || wtmp < 0)
6233 pg_fatal("weight specification out of range (0 .. %d): %lld",
6234 INT_MAX, (long long) wtmp);
6235 weight = wtmp;
6236 }
6237 else
6238 {
6239 *script = pg_strdup(option);
6240 weight = 1;
6241 }
6242
6243 return weight;
#define WSEP
Definition: pgbench.c:302

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

1917{
1918 int i = 1; /* starting at 1 skips the colon */
1919 char *name;
1920
1921 /* keep this logic in sync with valid_variable_name() */
1922 if (IS_HIGHBIT_SET(sql[i]) ||
1923 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1924 "_", sql[i]) != NULL)
1925 i++;
1926 else
1927 return NULL;
1928
1929 while (IS_HIGHBIT_SET(sql[i]) ||
1930 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1931 "_0123456789", sql[i]) != NULL)
1932 i++;
1933
1934 name = pg_malloc(i);
1935 memcpy(name, &sql[1], i - 1);
1936 name[i - 1] = '\0';
1937
1938 *eaten = i;
1939 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 1329 of file pgbench.c.

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

Referenced by evalStandardFunc().

◆ pg_time_now()

static pg_time_usec_t pg_time_now ( void  )
inlinestatic

◆ pg_time_now_lazy()

static void pg_time_now_lazy ( pg_time_usec_t now)
inlinestatic

Definition at line 887 of file pgbench.c.

889{
890 if ((*now) == 0)
891 (*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 5657 of file pgbench.c.

5659{
5660 char buffer[128];
5661 static int prepnum = 0;
5662
5663 Assert(my_command->type == SQL_COMMAND);
5664
5665 /* Save the first line for error display. */
5666 strlcpy(buffer, my_command->lines.data, sizeof(buffer));
5667 buffer[strcspn(buffer, "\n\r")] = '\0';
5668 my_command->first_line = pg_strdup(buffer);
5669
5670 /* Parse query and generate prepared statement name, if necessary */
5671 switch (querymode)
5672 {
5673 case QUERY_SIMPLE:
5674 my_command->argv[0] = my_command->lines.data;
5675 my_command->argc++;
5676 break;
5677 case QUERY_PREPARED:
5678 my_command->prepname = psprintf("P_%d", prepnum++);
5679 /* fall through */
5680 case QUERY_EXTENDED:
5681 if (!parseQuery(my_command))
5682 exit(1);
5683 break;
5684 default:
5685 exit(1);
5686 }
static bool parseQuery(Command *cmd)
Definition: pgbench.c:5476
size_t strlcpy(char *dst, const char *src, size_t siz)
Definition: strlcpy.c:45
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43

References Command::argc, Command::argv, Assert(), PQExpBufferData::data, 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 3117 of file pgbench.c.

3119{
3120 Command *command = sql_script[st->use_file].commands[command_num];
3121
3122 /* No prepare for non-SQL commands */
3123 if (command->type != SQL_COMMAND)
3124 return;
3125
3126 if (!st->prepared)
3128
3129 if (!st->prepared[st->use_file][command_num])
3130 {
3131 PGresult *res;
3132
3133 pg_log_debug("client %d preparing %s", st->id, command->prepname);
3134 res = PQprepare(st->con, command->prepname,
3135 command->argv[0], command->argc - 1, NULL);
3136 if (PQresultStatus(res) != PGRES_COMMAND_OK)
3137 pg_log_error("%s", PQerrorMessage(st->con));
3138 PQclear(res);
3139 st->prepared[st->use_file][command_num] = true;
3140 }
PGresult * PQprepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes)
Definition: fe-exec.c:2317
static void allocCStatePrepared(CState *st)
Definition: pgbench.c:3097

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

3152{
3153 int j;
3154 Command **commands = sql_script[st->use_file].commands;
3155
3156 Assert(commands[st->command]->type == META_COMMAND &&
3157 commands[st->command]->meta == META_STARTPIPELINE);
3158
3159 if (!st->prepared)
3161
3162 /*
3163 * We set the 'prepared' flag on the \startpipeline itself to flag that we
3164 * don't need to do this next time without calling prepareCommand(), even
3165 * though we don't actually prepare this command.
3166 */
3167 if (st->prepared[st->use_file][st->command])
3168 return;
3169
3170 for (j = st->command + 1; commands[j] != NULL; j++)
3171 {
3172 if (commands[j]->type == META_COMMAND &&
3173 commands[j]->meta == META_ENDPIPELINE)
3174 break;
3175
3176 prepareCommand(st, j);
3177 }
3178
3179 st->prepared[st->use_file][st->command] = true;
static void prepareCommand(CState *st, int command_num)
Definition: pgbench.c:3117

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

6271{
6272 /* generate and show report */
6273 pg_time_usec_t run = now - *last_report;
6274 int64 cnt,
6275 failures,
6276 retried;
6277 double tps,
6278 total_run,
6279 latency,
6280 sqlat,
6281 lag,
6282 stdev;
6283 char tbuf[315];
6284 StatsData cur;
6285
6286 /*
6287 * Add up the statistics of all threads.
6288 *
6289 * XXX: No locking. There is no guarantee that we get an atomic snapshot
6290 * of the transaction count and latencies, so these figures can well be
6291 * off by a small amount. The progress report's purpose is to give a
6292 * quick overview of how the test is going, so that shouldn't matter too
6293 * much. (If a read from a 64-bit integer is not atomic, you might get a
6294 * "torn" read and completely bogus latencies though!)
6295 */
6296 initStats(&cur, 0);
6297 for (int i = 0; i < nthreads; i++)
6298 {
6299 mergeSimpleStats(&cur.latency, &threads[i].stats.latency);
6300 mergeSimpleStats(&cur.lag, &threads[i].stats.lag);
6301 cur.cnt += threads[i].stats.cnt;
6302 cur.skipped += threads[i].stats.skipped;
6303 cur.retries += threads[i].stats.retries;
6304 cur.retried += threads[i].stats.retried;
6305 cur.serialization_failures +=
6307 cur.deadlock_failures += threads[i].stats.deadlock_failures;
6308 }
6309
6310 /* we count only actually executed transactions */
6311 cnt = cur.cnt - last->cnt;
6312 total_run = (now - test_start) / 1000000.0;
6313 tps = 1000000.0 * cnt / run;
6314 if (cnt > 0)
6315 {
6316 latency = 0.001 * (cur.latency.sum - last->latency.sum) / cnt;
6317 sqlat = 1.0 * (cur.latency.sum2 - last->latency.sum2) / cnt;
6318 stdev = 0.001 * sqrt(sqlat - 1000000.0 * latency * latency);
6319 lag = 0.001 * (cur.lag.sum - last->lag.sum) / cnt;
6320 }
6321 else
6322 {
6323 latency = sqlat = stdev = lag = 0;
6324 }
6325 failures = getFailures(&cur) - getFailures(last);
6326 retried = cur.retried - last->retried;
6327
6329 {
6330 snprintf(tbuf, sizeof(tbuf), "%.3f s",
6332 }
6333 else
6334 {
6335 /* round seconds are expected, but the thread may be late */
6336 snprintf(tbuf, sizeof(tbuf), "%.1f s", total_run);
6337 }
6338
6339 fprintf(stderr,
6340 "progress: %s, %.1f tps, lat %.3f ms stddev %.3f, " INT64_FORMAT " failed",
6341 tbuf, tps, latency, stdev, failures);
6342
6343 if (throttle_delay)
6344 {
6345 fprintf(stderr, ", lag %.3f ms", lag);
6346 if (latency_limit)
6347 fprintf(stderr, ", " INT64_FORMAT " skipped",
6348 cur.skipped - last->skipped);
6349 }
6350
6351 /* it can be non-zero only if max_tries is not equal to one */
6352 if (max_tries != 1)
6353 fprintf(stderr,
6354 ", " INT64_FORMAT " retried, " INT64_FORMAT " retries",
6355 retried, cur.retries - last->retries);
6356 fprintf(stderr, "\n");
6357
6358 *last = cur;
6359 *last_report = now;
struct cursor * cur
Definition: ecpg.c:29
static int64 getFailures(const StatsData *stats)
Definition: pgbench.c:4547

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

6413{
6414 /* tps is about actually executed transactions during benchmarking */
6415 int64 failures = getFailures(total);
6416 int64 total_cnt = total->cnt + total->skipped + failures;
6417 double bench_duration = PG_TIME_GET_DOUBLE(total_duration);
6418 double tps = total->cnt / bench_duration;
6419
6420 /* Report test parameters. */
6421 printf("transaction type: %s\n",
6422 num_scripts == 1 ? sql_script[0].desc : "multiple scripts");
6423 printf("scaling factor: %d\n", scale);
6424 /* only print partitioning information if some partitioning was detected */
6426 printf("partition method: %s\npartitions: %d\n",
6428 printf("query mode: %s\n", QUERYMODE[querymode]);
6429 printf("number of clients: %d\n", nclients);
6430 printf("number of threads: %d\n", nthreads);
6431
6432 if (max_tries)
6433 printf("maximum number of tries: %u\n", max_tries);
6434
6435 if (duration <= 0)
6436 {
6437 printf("number of transactions per client: %d\n", nxacts);
6438 printf("number of transactions actually processed: " INT64_FORMAT "/%d\n",
6439 total->cnt, nxacts * nclients);
6440 }
6441 else
6442 {
6443 printf("duration: %d s\n", duration);
6444 printf("number of transactions actually processed: " INT64_FORMAT "\n",
6445 total->cnt);
6446 }
6447
6448 /*
6449 * Remaining stats are nonsensical if we failed to execute any xacts due
6450 * to others than serialization or deadlock errors
6451 */
6452 if (total_cnt <= 0)
6453 return;
6454
6455 printf("number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6456 failures, 100.0 * failures / total_cnt);
6457
6459 {
6460 printf("number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6462 100.0 * total->serialization_failures / total_cnt);
6463 printf("number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6464 total->deadlock_failures,
6465 100.0 * total->deadlock_failures / total_cnt);
6466 }
6467
6468 /* it can be non-zero only if max_tries is not equal to one */
6469 if (max_tries != 1)
6470 {
6471 printf("number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6472 total->retried, 100.0 * total->retried / total_cnt);
6473 printf("total number of retries: " INT64_FORMAT "\n", total->retries);
6474 }
6475
6477 printf("number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6478 total->skipped, 100.0 * total->skipped / total_cnt);
6479
6480 if (latency_limit)
6481 printf("number of transactions above the %.1f ms latency limit: " INT64_FORMAT "/" INT64_FORMAT " (%.3f%%)\n",
6482 latency_limit / 1000.0, latency_late, total->cnt,
6483 (total->cnt > 0) ? 100.0 * latency_late / total->cnt : 0.0);
6484
6486 printSimpleStats("latency", &total->latency);
6487 else
6488 {
6489 /* no measurement, show average latency computed from run time */
6490 printf("latency average = %.3f ms%s\n",
6491 0.001 * total_duration * nclients / total_cnt,
6492 failures > 0 ? " (including failures)" : "");
6493 }
6494
6495 if (throttle_delay)
6496 {
6497 /*
6498 * Report average transaction lag under rate limit throttling. This
6499 * is the delay between scheduled and actual start times for the
6500 * transaction. The measured lag may be caused by thread/client load,
6501 * the database load, or the Poisson throttling process.
6502 */
6503 printf("rate limit schedule lag: avg %.3f (max %.3f) ms\n",
6504 0.001 * total->lag.sum / total->cnt, 0.001 * total->lag.max);
6505 }
6506
6507 /*
6508 * Under -C/--connect, each transaction incurs a significant connection
6509 * cost, it would not make much sense to ignore it in tps, and it would
6510 * not be tps anyway.
6511 *
6512 * Otherwise connections are made just once at the beginning of the run
6513 * and should not impact performance but for very short run, so they are
6514 * (right)fully ignored in tps.
6515 */
6516 if (is_connect)
6517 {
6518 printf("average connection time = %.3f ms\n", 0.001 * conn_total_duration / (total->cnt + failures));
6519 printf("tps = %f (including reconnection times)\n", tps);
6520 }
6521 else
6522 {
6523 printf("initial connection time = %.3f ms\n", 0.001 * conn_elapsed_duration);
6524 printf("tps = %f (without initial connection time)\n", tps);
6525 }
6526
6527 /* Report per-script/command statistics */
6529 {
6530 int i;
6531
6532 for (i = 0; i < num_scripts; i++)
6533 {
6534 if (per_script_stats)
6535 {
6536 StatsData *sstats = &sql_script[i].stats;
6537 int64 script_failures = getFailures(sstats);
6538 int64 script_total_cnt =
6539 sstats->cnt + sstats->skipped + script_failures;
6540
6541 printf("SQL script %d: %s\n"
6542 " - weight: %d (targets %.1f%% of total)\n"
6543 " - " INT64_FORMAT " transactions (%.1f%% of total)\n",
6544 i + 1, sql_script[i].desc,
6545 sql_script[i].weight,
6546 100.0 * sql_script[i].weight / total_weight,
6547 script_total_cnt,
6548 100.0 * script_total_cnt / total_cnt);
6549
6550 if (script_total_cnt > 0)
6551 {
6552 printf(" - number of transactions actually processed: " INT64_FORMAT " (tps = %f)\n",
6553 sstats->cnt, sstats->cnt / bench_duration);
6554
6555 printf(" - number of failed transactions: " INT64_FORMAT " (%.3f%%)\n",
6556 script_failures,
6557 100.0 * script_failures / script_total_cnt);
6558
6560 {
6561 printf(" - number of serialization failures: " INT64_FORMAT " (%.3f%%)\n",
6562 sstats->serialization_failures,
6563 (100.0 * sstats->serialization_failures /
6564 script_total_cnt));
6565 printf(" - number of deadlock failures: " INT64_FORMAT " (%.3f%%)\n",
6566 sstats->deadlock_failures,
6567 (100.0 * sstats->deadlock_failures /
6568 script_total_cnt));
6569 }
6570
6571 /*
6572 * it can be non-zero only if max_tries is not equal to
6573 * one
6574 */
6575 if (max_tries != 1)
6576 {
6577 printf(" - number of transactions retried: " INT64_FORMAT " (%.3f%%)\n",
6578 sstats->retried,
6579 100.0 * sstats->retried / script_total_cnt);
6580 printf(" - total number of retries: " INT64_FORMAT "\n",
6581 sstats->retries);
6582 }
6583
6585 printf(" - number of transactions skipped: " INT64_FORMAT " (%.3f%%)\n",
6586 sstats->skipped,
6587 100.0 * sstats->skipped / script_total_cnt);
6588
6589 }
6590 printSimpleStats(" - latency", &sstats->latency);
6591 }
6592
6593 /*
6594 * Report per-command statistics: latencies, retries after errors,
6595 * failures (errors without retrying).
6596 */
6598 {
6599 Command **commands;
6600
6601 printf("%sstatement latencies in milliseconds%s:\n",
6602 per_script_stats ? " - " : "",
6603 (max_tries == 1 ?
6604 " and failures" :
6605 ", failures and retries"));
6606
6607 for (commands = sql_script[i].commands;
6608 *commands != NULL;
6609 commands++)
6610 {
6611 SimpleStats *cstats = &(*commands)->stats;
6612
6613 if (max_tries == 1)
6614 printf(" %11.3f %10" PRId64 " %s\n",
6615 (cstats->count > 0) ?
6616 1000.0 * cstats->sum / cstats->count : 0.0,
6617 (*commands)->failures,
6618 (*commands)->first_line);
6619 else
6620 printf(" %11.3f %10" PRId64 " %10" PRId64 " %s\n",
6621 (cstats->count > 0) ?
6622 1000.0 * cstats->sum / cstats->count : 0.0,
6623 (*commands)->failures,
6624 (*commands)->retries,
6625 (*commands)->first_line);
6626 }
6627 }
6628 }
6629 }
static void printSimpleStats(const char *prefix, SimpleStats *ss)
Definition: pgbench.c:6362
#define printf(...)
Definition: port.h:245
StatsData stats
Definition: pgbench.c:762

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

6364{
6365 if (ss->count > 0)
6366 {
6367 double latency = ss->sum / ss->count;
6368 double stddev = sqrt(ss->sum2 / ss->count - latency * latency);
6369
6370 printf("%s average = %.3f ms\n", prefix, 0.001 * latency);
6371 printf("%s stddev = %.3f ms\n", prefix, 0.001 * stddev);
6372 }

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

3594{
3595 static PQExpBuffer buf = NULL;
3596
3597 if (buf == NULL)
3599 else
3601
3602 printfPQExpBuffer(buf, "client %d ", st->id);
3603 appendPQExpBufferStr(buf, (is_retry ?
3604 "repeats the transaction after the error" :
3605 "ends the failed transaction"));
3606 appendPQExpBuffer(buf, " (try %u", st->tries);
3607
3608 /* Print max_tries if it is not unlimited. */
3609 if (max_tries)
3611
3612 /*
3613 * If the latency limit is used, print a percentage of the current
3614 * transaction latency from the latency limit.
3615 */
3616 if (latency_limit)
3617 {
3619 appendPQExpBuffer(buf, ", %.3f%% of the maximum time of tries was used",
3620 (100.0 * (*now - st->txn_scheduled) / latency_limit));
3621 }
3622 appendPQExpBufferStr(buf, ")\n");
3623
3624 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 6376 of file pgbench.c.

6378{
6379 int server_ver = PQserverVersion(con);
6380 int client_ver = PG_VERSION_NUM;
6381
6382 if (server_ver != client_ver)
6383 {
6384 const char *server_version;
6385 char sverbuf[32];
6386
6387 /* Try to get full text form, might include "devel" etc */
6388 server_version = PQparameterStatus(con, "server_version");
6389 /* Otherwise fall back on server_ver */
6390 if (!server_version)
6391 {
6392 formatPGVersionNumber(server_ver, true,
6393 sverbuf, sizeof(sverbuf));
6394 server_version = sverbuf;
6395 }
6396
6397 printf(_("%s (%s, server %s)\n"),
6398 "pgbench", PG_VERSION, server_version);
6399 }
6400 /* For version match, only print pgbench version */
6401 else
6402 printf("%s (%s)\n", "pgbench", PG_VERSION);
6403 fflush(stdout);
#define _(x)
Definition: elog.c:91
const char * PQparameterStatus(const PGconn *conn, const char *paramName)
Definition: fe-connect.c:7634
static int server_version
Definition: pg_dumpall.c:109
char * formatPGVersionNumber(int version_number, bool include_minor, char *buf, size_t buflen)
Definition: string_utils.c:313

References _, 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,
int  lineno,
int  start_offset 
)
static

Definition at line 5694 of file pgbench.c.

5697{
5698 Command *my_command;
5699 PQExpBufferData word_buf;
5700 int word_offset;
5701 int offsets[MAX_ARGS]; /* offsets of argument words */
5702 int j;
5703
5704 initPQExpBuffer(&word_buf);
5705
5706 /* Collect first word of command */
5707 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5708 {
5709 termPQExpBuffer(&word_buf);
5710 return NULL;
5711 }
5712
5713 /* Allocate and initialize Command structure */
5714 my_command = (Command *) pg_malloc0(sizeof(Command));
5715 my_command->type = META_COMMAND;
5716 my_command->argc = 0;
5717 initSimpleStats(&my_command->stats);
5718
5719 /* Save first word (command name) */
5720 j = 0;
5721 offsets[j] = word_offset;
5722 my_command->argv[j++] = pg_strdup(word_buf.data);
5723 my_command->argc++;
5724
5725 /* ... and convert it to enum form */
5726 my_command->meta = getMetaCommand(my_command->argv[0]);
5727
5728 if (my_command->meta == META_SET ||
5729 my_command->meta == META_IF ||
5730 my_command->meta == META_ELIF)
5731 {
5732 yyscan_t yyscanner;
5733
5734 /* For \set, collect var name */
5735 if (my_command->meta == META_SET)
5736 {
5737 if (!expr_lex_one_word(sstate, &word_buf, &word_offset))
5738 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5739 "missing argument", NULL, -1);
5740
5741 offsets[j] = word_offset;
5742 my_command->argv[j++] = pg_strdup(word_buf.data);
5743 my_command->argc++;
5744 }
5745
5746 /* then for all parse the expression */
5747 yyscanner = expr_scanner_init(sstate, source, lineno, start_offset,
5748 my_command->argv[0]);
5749
5750 if (expr_yyparse(&my_command->expr, yyscanner) != 0)
5751 {
5752 /* dead code: exit done from syntax_error called by yyerror */
5753 exit(1);
5754 }
5755
5756 /* Save line, trimming any trailing newline */
5757 my_command->first_line =
5759 start_offset,
5760 true);
5761
5762 expr_scanner_finish(yyscanner);
5763
5764 termPQExpBuffer(&word_buf);
5765
5766 return my_command;
5767 }
5768
5769 /* For all other commands, collect remaining words. */
5770 while (expr_lex_one_word(sstate, &word_buf, &word_offset))
5771 {
5772 /*
5773 * my_command->argv[0] is the command itself, so the max number of
5774 * arguments is one less than MAX_ARGS
5775 */
5776 if (j >= MAX_ARGS)
5777 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5778 "too many arguments", NULL, -1);
5779
5780 offsets[j] = word_offset;
5781 my_command->argv[j++] = pg_strdup(word_buf.data);
5782 my_command->argc++;
5783 }
5784
5785 /* Save line, trimming any trailing newline */
5786 my_command->first_line =
5788 start_offset,
5789 true);
5790
5791 if (my_command->meta == META_SLEEP)
5792 {
5793 if (my_command->argc < 2)
5794 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5795 "missing argument", NULL, -1);
5796
5797 if (my_command->argc > 3)
5798 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5799 "too many arguments", NULL,
5800 offsets[3] - start_offset);
5801
5802 /*
5803 * Split argument into number and unit to allow "sleep 1ms" etc. We
5804 * don't have to terminate the number argument with null because it
5805 * will be parsed with atoi, which ignores trailing non-digit
5806 * characters.
5807 */
5808 if (my_command->argv[1][0] != ':')
5809 {
5810 char *c = my_command->argv[1];
5811 bool have_digit = false;
5812
5813 /* Skip sign */
5814 if (*c == '+' || *c == '-')
5815 c++;
5816
5817 /* Require at least one digit */
5818 if (*c && isdigit((unsigned char) *c))
5819 have_digit = true;
5820
5821 /* Eat all digits */
5822 while (*c && isdigit((unsigned char) *c))
5823 c++;
5824
5825 if (*c)
5826 {
5827 if (my_command->argc == 2 && have_digit)
5828 {
5829 my_command->argv[2] = c;
5830 offsets[2] = offsets[1] + (c - my_command->argv[1]);
5831 my_command->argc = 3;
5832 }
5833 else
5834 {
5835 /*
5836 * Raise an error if argument starts with non-digit
5837 * character (after sign).
5838 */
5839 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5840 "invalid sleep time, must be an integer",
5841 my_command->argv[1], offsets[1] - start_offset);
5842 }
5843 }
5844 }
5845
5846 if (my_command->argc == 3)
5847 {
5848 if (pg_strcasecmp(my_command->argv[2], "us") != 0 &&
5849 pg_strcasecmp(my_command->argv[2], "ms") != 0 &&
5850 pg_strcasecmp(my_command->argv[2], "s") != 0)
5851 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5852 "unrecognized time unit, must be us, ms or s",
5853 my_command->argv[2], offsets[2] - start_offset);
5854 }
5855 }
5856 else if (my_command->meta == META_SETSHELL)
5857 {
5858 if (my_command->argc < 3)
5859 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5860 "missing argument", NULL, -1);
5861 }
5862 else if (my_command->meta == META_SHELL)
5863 {
5864 if (my_command->argc < 2)
5865 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5866 "missing command", NULL, -1);
5867 }
5868 else if (my_command->meta == META_ELSE || my_command->meta == META_ENDIF ||
5869 my_command->meta == META_STARTPIPELINE ||
5870 my_command->meta == META_ENDPIPELINE ||
5871 my_command->meta == META_SYNCPIPELINE)
5872 {
5873 if (my_command->argc != 1)
5874 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5875 "unexpected argument", NULL, -1);
5876 }
5877 else if (my_command->meta == META_GSET || my_command->meta == META_ASET)
5878 {
5879 if (my_command->argc > 2)
5880 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5881 "too many arguments", NULL, -1);
5882 }
5883 else
5884 {
5885 /* my_command->meta == META_NONE */
5886 syntax_error(source, lineno, my_command->first_line, my_command->argv[0],
5887 "invalid command", NULL, -1);
5888 }
5889
5890 termPQExpBuffer(&word_buf);
5891
5892 return my_command;
void * yyscan_t
Definition: cubedata.h:65
bool expr_lex_one_word(PsqlScanState state, PQExpBuffer word_buf, int *offset)
Definition: exprscan.l:318
char * expr_scanner_get_substring(PsqlScanState state, int start_offset, bool chomp)
Definition: exprscan.l:425
void expr_scanner_finish(yyscan_t yyscanner)
Definition: exprscan.l:402
yyscan_t expr_scanner_init(PsqlScanState state, const char *source, int lineno, int start_offset, const char *command)
Definition: exprscan.l:370
static rewind_source * source
Definition: pg_rewind.c:89
static MetaCommand getMetaCommand(const char *cmd)
Definition: pgbench.c:2901
int expr_yyparse(PgBenchExpr **expr_parse_result_p, yyscan_t yyscanner)

References Command::argc, Command::argv, PQExpBufferData::data, Command::expr, expr_lex_one_word(), expr_scanner_finish(), expr_scanner_get_substring(), expr_scanner_init(), 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(), and Command::type.

Referenced by ParseScript().

◆ process_builtin()

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

Definition at line 6155 of file pgbench.c.

6157{
6158 ParseScript(bi->script, bi->desc, weight);
static void ParseScript(const char *script, const char *desc, int weight)
Definition: pgbench.c:5955

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

6131{
6132 FILE *fd;
6133 char *buf;
6134
6135 /* Slurp the file contents into "buf" */
6136 if (strcmp(filename, "-") == 0)
6137 fd = stdin;
6138 else if ((fd = fopen(filename, "r")) == NULL)
6139 pg_fatal("could not open file \"%s\": %m", filename);
6140
6142
6143 if (ferror(fd))
6144 pg_fatal("could not read file \"%s\": %m", filename);
6145
6146 if (fd != stdin)
6147 fclose(fd);
6148
6149 ParseScript(buf, filename, weight);
6150
6151 free(buf);
static char * filename
Definition: pg_dumpall.c:120
static char * read_file_contents(FILE *fd)
Definition: pgbench.c:6096

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

4712{
4713 double latency = 0.0,
4714 lag = 0.0;
4715 bool detailed = progress || throttle_delay || latency_limit ||
4717
4718 if (detailed && !skipped && st->estatus == ESTATUS_NO_ERROR)
4719 {
4721
4722 /* compute latency & lag */
4723 latency = (*now) - st->txn_scheduled;
4724 lag = st->txn_begin - st->txn_scheduled;
4725 }
4726
4727 /* keep detailed thread stats */
4728 accumStats(&thread->stats, skipped, latency, lag, st->estatus, st->tries);
4729
4730 /* count transactions over the latency limit, if needed */
4731 if (latency_limit && latency > latency_limit)
4732 thread->latency_late++;
4733
4734 /* client stat is just counting */
4735 st->cnt++;
4736
4737 if (use_log)
4738 doLog(thread, st, agg, skipped, latency, lag);
4739
4740 /* XXX could use a mutex here, but we choose not to */
4741 if (per_script_stats)
4742 accumStats(&sql_script[st->use_file].stats, skipped, latency, lag,
4743 st->estatus, st->tries);
static void doLog(TState *thread, CState *st, StatsData *agg, bool skipped, double latency, double lag)
Definition: pgbench.c:4589

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

1858{
1859 Variable *var;
1860 char *val;
1861
1862 var = lookupCreateVariable(variables, context, name);
1863 if (!var)
1864 return false;
1865
1866 /* dup then free, in case value is pointing at this variable */
1867 val = pg_strdup(value);
1868
1869 free(var->svalue);
1870 var->svalue = val;
1871 var->value.type = PGBT_NO_VALUE;
1872
1873 return true;
static struct @166 value
static Variable * lookupCreateVariable(Variables *variables, const char *context, char *name)
Definition: pgbench.c:1818

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

1900{
1902
1904 return putVariableValue(variables, context, name, &val);

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

1881{
1882 Variable *var;
1883
1884 var = lookupCreateVariable(variables, context, name);
1885 if (!var)
1886 return false;
1887
1888 free(var->svalue);
1889 var->svalue = NULL;
1890 var->value = *value;
1891
1892 return true;

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

6098{
6099 char *buf;
6100 size_t buflen = BUFSIZ;
6101 size_t used = 0;
6102
6103 buf = (char *) pg_malloc(buflen);
6104
6105 for (;;)
6106 {
6107 size_t nread;
6108
6109 nread = fread(buf + used, 1, BUFSIZ, fd);
6110 used += nread;
6111 /* If fread() read less than requested, must be EOF or error */
6112 if (nread < BUFSIZ)
6113 break;
6114 /* Enlarge buf so we can read some more */
6115 buflen += BUFSIZ;
6116 buf = (char *) pg_realloc(buf, buflen);
6117 }
6118 /* There is surely room for a terminator */
6119 buf[used] = '\0';
6120
6121 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 3269 of file pgbench.c.

3271{
3272 PGresult *res;
3273 PGresult *next_res;
3274 int qrynum = 0;
3275
3276 /*
3277 * varprefix should be set only with \gset or \aset, and \endpipeline and
3278 * SQL commands do not need it.
3279 */
3280 Assert((meta == META_NONE && varprefix == NULL) ||
3281 ((meta == META_ENDPIPELINE) && varprefix == NULL) ||
3282 ((meta == META_GSET || meta == META_ASET) && varprefix != NULL));
3283
3284 res = PQgetResult(st->con);
3285
3286 while (res != NULL)
3287 {
3288 bool is_last;
3289
3290 /* peek at the next result to know whether the current is last */
3291 next_res = PQgetResult(st->con);
3292 is_last = (next_res == NULL);
3293
3294 switch (PQresultStatus(res))
3295 {
3296 case PGRES_COMMAND_OK: /* non-SELECT commands */
3297 case PGRES_EMPTY_QUERY: /* may be used for testing no-op overhead */
3298 if (is_last && meta == META_GSET)
3299 {
3300 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3301 st->id, st->use_file, st->command, qrynum, 0);
3303 goto error;
3304 }
3305 break;
3306
3307 case PGRES_TUPLES_OK:
3308 if ((is_last && meta == META_GSET) || meta == META_ASET)
3309 {
3310 int ntuples = PQntuples(res);
3311
3312 if (meta == META_GSET && ntuples != 1)
3313 {
3314 /* under \gset, report the error */
3315 pg_log_error("client %d script %d command %d query %d: expected one row, got %d",
3316 st->id, st->use_file, st->command, qrynum, PQntuples(res));
3318 goto error;
3319 }
3320 else if (meta == META_ASET && ntuples <= 0)
3321 {
3322 /* coldly skip empty result under \aset */
3323 break;
3324 }
3325
3326 /* store results into variables */
3327 for (int fld = 0; fld < PQnfields(res); fld++)
3328 {
3329 char *varname = PQfname(res, fld);
3330
3331 /* allocate varname only if necessary, freed below */
3332 if (*varprefix != '\0')
3333 varname = psprintf("%s%s", varprefix, varname);
3334
3335 /* store last row result as a string */
3336 if (!putVariable(&st->variables, meta == META_ASET ? "aset" : "gset", varname,
3337 PQgetvalue(res, ntuples - 1, fld)))
3338 {
3339 /* internal error */
3340 pg_log_error("client %d script %d command %d query %d: error storing into variable %s",
3341 st->id, st->use_file, st->command, qrynum, varname);
3343 goto error;
3344 }
3345
3346 if (*varprefix != '\0')
3347 pg_free(varname);
3348 }
3349 }
3350 /* otherwise the result is simply thrown away by PQclear below */
3351 break;
3352
3354 pg_log_debug("client %d pipeline ending, ongoing syncs: %d",
3355 st->id, st->num_syncs);
3356 st->num_syncs--;
3357 if (st->num_syncs == 0 && PQexitPipelineMode(st->con) != 1)
3358 pg_log_error("client %d failed to exit pipeline mode: %s", st->id,
3359 PQerrorMessage(st->con));
3360 break;
3361
3363 case PGRES_FATAL_ERROR:
3366 if (canRetryError(st->estatus))
3367 {
3368 if (verbose_errors)
3370 goto error;
3371 }
3372 /* fall through */
3373
3374 default:
3375 /* anything else is unexpected */
3376 pg_log_error("client %d script %d aborted in command %d query %d: %s",
3377 st->id, st->use_file, st->command, qrynum,
3378 PQerrorMessage(st->con));
3379 goto error;
3380 }
3381
3382 PQclear(res);
3383 qrynum++;
3384 res = next_res;
3385 }
3386
3387 if (qrynum == 0)
3388 {
3389 pg_log_error("client %d command %d: no results", st->id, st->command);
3390 return false;
3391 }
3392
3393 return true;
3394
3395error:
3396 PQclear(res);
3397 PQclear(next_res);
3398 do
3399 {
3400 res = PQgetResult(st->con);
3401 PQclear(res);
3402 } while (res);
3403
3404 return false;
#define PQnfields
Definition: libpq-be-fe.h:252
#define PQfname
Definition: libpq-be-fe.h:256
@ PGRES_FATAL_ERROR
Definition: libpq-fe.h:136
@ PGRES_EMPTY_QUERY
Definition: libpq-fe.h:124
@ PGRES_NONFATAL_ERROR
Definition: libpq-fe.h:135
static EStatus getSQLErrorStatus(const char *sqlState)
Definition: pgbench.c:3236
static void commandError(CState *st, const char *message)
Definition: pgbench.c:3059
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(), 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 1942 of file pgbench.c.

1944{
1945 int valueln = strlen(value);
1946
1947 if (valueln > len)
1948 {
1949 size_t offset = param - *sql;
1950
1951 *sql = pg_realloc(*sql, strlen(*sql) - len + valueln + 1);
1952 param = *sql + offset;
1953 }
1954
1955 if (valueln != len)
1956 memmove(param + valueln, param + len, strlen(param + len) + 1);
1957 memcpy(param, value, valueln);
1958
1959 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 5282 of file pgbench.c.

5284{
5285 PQExpBufferData stats;
5286 PGconn *con;
5287 const char *step;
5288 double run_time = 0.0;
5289 bool first = true;
5290
5291 initPQExpBuffer(&stats);
5292
5293 if ((con = doConnect()) == NULL)
5294 pg_fatal("could not create connection for initialization");
5295
5297 SetCancelConn(con);
5298
5299 for (step = initialize_steps; *step != '\0'; step++)
5300 {
5301 char *op = NULL;
5303
5304 switch (*step)
5305 {
5306 case 'd':
5307 op = "drop tables";
5308 initDropTables(con);
5309 break;
5310 case 't':
5311 op = "create tables";
5312 initCreateTables(con);
5313 break;
5314 case 'g':
5315 op = "client-side generate";
5317 break;
5318 case 'G':
5319 op = "server-side generate";
5321 break;
5322 case 'v':
5323 op = "vacuum";
5324 initVacuum(con);
5325 break;
5326 case 'p':
5327 op = "primary keys";
5328 initCreatePKeys(con);
5329 break;
5330 case 'f':
5331 op = "foreign keys";
5332 initCreateFKeys(con);
5333 break;
5334 case ' ':
5335 break; /* ignore */
5336 default:
5337 pg_log_error("unrecognized initialization step \"%c\"", *step);
5338 PQfinish(con);
5339 exit(1);
5340 }
5341
5342 if (op != NULL)
5343 {
5344 double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
5345
5346 if (!first)
5347 appendPQExpBufferStr(&stats, ", ");
5348 else
5349 first = false;
5350
5351 appendPQExpBuffer(&stats, "%s %.2f s", op, elapsed_sec);
5352
5353 run_time += elapsed_sec;
5354 }
5355 }
5356
5357 fprintf(stderr, "done in %.2f s (%s).\n", run_time, stats.data);
5359 PQfinish(con);
5360 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:5198
static void initDropTables(PGconn *con)
Definition: pgbench.c:4760
static void initGenerateDataServerSide(PGconn *con)
Definition: pgbench.c:5140
static void initCreateFKeys(PGconn *con)
Definition: pgbench.c:5236
static void initVacuum(PGconn *con)
Definition: pgbench.c:5185
static void initCreateTables(PGconn *con)
Definition: pgbench.c:4851
static void initGenerateDataClientSide(PGconn *con)
Definition: pgbench.c:5108

References appendPQExpBuffer(), appendPQExpBufferStr(), PQExpBufferData::data, doConnect(), 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 2943 of file pgbench.c.

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

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

Referenced by executeMetaCommand().

◆ sendCommand()

static bool sendCommand ( CState st,
Command command 
)
static

Definition at line 3183 of file pgbench.c.

3185{
3186 int r;
3187
3188 if (querymode == QUERY_SIMPLE)
3189 {
3190 char *sql;
3191
3192 sql = pg_strdup(command->argv[0]);
3193 sql = assignVariables(&st->variables, sql);
3194
3195 pg_log_debug("client %d sending %s", st->id, sql);
3196 r = PQsendQuery(st->con, sql);
3197 free(sql);
3198 }
3199 else if (querymode == QUERY_EXTENDED)
3200 {
3201 const char *sql = command->argv[0];
3202 const char *params[MAX_ARGS];
3203
3204 getQueryParams(&st->variables, command, params);
3205
3206 pg_log_debug("client %d sending %s", st->id, sql);
3207 r = PQsendQueryParams(st->con, sql, command->argc - 1,
3208 NULL, params, NULL, NULL, 0);
3209 }
3210 else if (querymode == QUERY_PREPARED)
3211 {
3212 const char *params[MAX_ARGS];
3213
3214 prepareCommand(st, st->command);
3215 getQueryParams(&st->variables, command, params);
3216
3217 pg_log_debug("client %d sending %s", st->id, command->prepname);
3218 r = PQsendQueryPrepared(st->con, command->prepname, command->argc - 1,
3219 params, NULL, NULL, 0);
3220 }
3221 else /* unknown sql mode */
3222 r = 0;
3223
3224 if (r == 0)
3225 {
3226 pg_log_debug("client %d could not send %s", st->id, command->argv[0]);
3227 return false;
3228 }
3229 else
3230 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:1503
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:1644
static void getQueryParams(Variables *variables, const Command *command, const char **params)
Definition: pgbench.c:1998
static char * assignVariables(Variables *variables, char *sql)
Definition: pgbench.c:1962

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

6638{
6639 uint64 iseed;
6640
6641 if (seed == NULL || strcmp(seed, "time") == 0)
6642 {
6643 /* rely on current time */
6644 iseed = pg_time_now();
6645 }
6646 else if (strcmp(seed, "rand") == 0)
6647 {
6648 /* use some "strong" random source */
6649 if (!pg_strong_random(&iseed, sizeof(iseed)))
6650 {
6651 pg_log_error("could not generate random seed");
6652 return false;
6653 }
6654 }
6655 else
6656 {
6657 char garbage;
6658
6659 if (sscanf(seed, "%" SCNu64 "%c", &iseed, &garbage) != 1)
6660 {
6661 pg_log_error("unrecognized random seed option \"%s\"", seed);
6662 pg_log_error_detail("Expecting an unsigned integer, \"time\" or \"rand\".");
6663 return false;
6664 }
6665 }
6666
6667 if (seed != NULL)
6668 pg_log_info("setting random seed to %" PRIu64, iseed);
6669
6670 random_seed = iseed;
6671
6672 /* Initialize base_random_sequence using seed */
6674
6675 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 7791 of file pgbench.c.

7793{
7795 alarm(seconds);
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: pgbench.c:7785
#define pqsignal
Definition: port.h:531
#define SIGALRM
Definition: win32_port.h:164

References handle_sig_alarm(), pqsignal, and SIGALRM.

Referenced by main().

◆ setBoolValue()

static void setBoolValue ( PgBenchValue pv,
bool  bval 
)
static

Definition at line 2128 of file pgbench.c.

2130{
2131 pv->type = PGBT_BOOLEAN;
2132 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 2144 of file pgbench.c.

2146{
2147 pv->type = PGBT_DOUBLE;
2148 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 2136 of file pgbench.c.

2138{
2139 pv->type = PGBT_INT;
2140 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 2120 of file pgbench.c.

2122{
2123 pv->type = PGBT_NULL;
2124 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 5573 of file pgbench.c.

5575{
5576 char *p = sql_command;
5577
5578 /* Skip any leading whitespace, as well as "--" style comments */
5579 for (;;)
5580 {
5581 if (isspace((unsigned char) *p))
5582 p++;
5583 else if (strncmp(p, "--", 2) == 0)
5584 {
5585 p = strchr(p, '\n');
5586 if (p == NULL)
5587 return NULL;
5588 p++;
5589 }
5590 else
5591 break;
5592 }
5593
5594 /* NULL if there's nothing but whitespace and comments */
5595 if (*p == '\0')
5596 return NULL;
5597
5598 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 7995 of file pgbench.c.

7997{
7998 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 1085 of file pgbench.c.

1087{
1088 char *end;
1089
1090 errno = 0;
1091 *dv = strtod(str, &end);
1092
1093 if (unlikely(errno != 0))
1094 {
1095 if (!errorOK)
1096 pg_log_error("value \"%s\" is out of range for type double", str);
1097 return false;
1098 }
1099
1100 if (unlikely(end == str || *end != '\0'))
1101 {
1102 if (!errorOK)
1103 pg_log_error("invalid input syntax for type double: \"%s\"", str);
1104 return false;
1105 }
1106 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 1014 of file pgbench.c.

1016{
1017 const char *ptr = str;
1018 int64 tmp = 0;
1019 bool neg = false;
1020
1021 /*
1022 * Do our own scan, rather than relying on sscanf which might be broken
1023 * for long long.
1024 *
1025 * As INT64_MIN can't be stored as a positive 64 bit integer, accumulate
1026 * value as a negative number.
1027 */
1028
1029 /* skip leading spaces */
1030 while (*ptr && isspace((unsigned char) *ptr))
1031 ptr++;
1032
1033 /* handle sign */
1034 if (*ptr == '-')
1035 {
1036 ptr++;
1037 neg = true;
1038 }
1039 else if (*ptr == '+')
1040 ptr++;
1041
1042 /* require at least one digit */
1043 if (unlikely(!isdigit((unsigned char) *ptr)))
1044 goto invalid_syntax;
1045
1046 /* process digits */
1047 while (*ptr && isdigit((unsigned char) *ptr))
1048 {
1049 int8 digit = (*ptr++ - '0');
1050
1051 if (unlikely(pg_mul_s64_overflow(tmp, 10, &tmp)) ||
1052 unlikely(pg_sub_s64_overflow(tmp, digit, &tmp)))
1053 goto out_of_range;
1054 }
1055
1056 /* allow trailing whitespace, but not other trailing chars */
1057 while (*ptr != '\0' && isspace((unsigned char) *ptr))
1058 ptr++;
1059
1060 if (unlikely(*ptr != '\0'))
1061 goto invalid_syntax;
1062
1063 if (!neg)
1064 {
1065 if (unlikely(tmp == PG_INT64_MIN))
1066 goto out_of_range;
1067 tmp = -tmp;
1068 }
1069
1070 *result = tmp;
1071 return true;
1072
1073out_of_range:
1074 if (!errorOK)
1075 pg_log_error("value \"%s\" is out of range for type bigint", str);
1076 return false;
1077
1078invalid_syntax:
1079 if (!errorOK)
1080 pg_log_error("invalid input syntax for type bigint: \"%s\"", str);
1081 return false;
int8_t int8
Definition: c.h:533

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

5541{
5543
5545
5546 printfPQExpBuffer(&buf, "%s:%d: %s", source, lineno, msg);
5547 if (more != NULL)
5548 appendPQExpBuffer(&buf, " (%s)", more);
5549 if (column >= 0 && line == NULL)
5550 appendPQExpBuffer(&buf, " at column %d", column + 1);
5551 if (command != NULL)
5552 appendPQExpBuffer(&buf, " in command \"%s\"", command);
5553
5554 pg_log_error("%s", buf.data);
5555
5557
5558 if (line != NULL)
5559 {
5560 fprintf(stderr, "%s\n", line);
5561 if (column >= 0)
5562 fprintf(stderr, "%*c error found here\n", column + 1, '^');
5563 }
5564
5565 exit(1);

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

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

◆ threadRun()

static THREAD_FUNC_RETURN_TYPE THREAD_FUNC_CC threadRun ( void *  arg)
static

Definition at line 7469 of file pgbench.c.

7471{
7472 TState *thread = (TState *) arg;
7473 CState *state = thread->state;
7475 int nstate = thread->nstate;
7476 int remains = nstate; /* number of remaining clients */
7477 socket_set *sockets = alloc_socket_set(nstate);
7478 int64 thread_start,
7479 last_report,
7480 next_report;
7481 StatsData last,
7482 aggs;
7483
7484 /* open log file if requested */
7485 if (use_log)
7486 {
7487 char logpath[MAXPGPATH];
7488 char *prefix = logfile_prefix ? logfile_prefix : "pgbench_log";
7489
7490 if (thread->tid == 0)
7491 snprintf(logpath, sizeof(logpath), "%s.%d", prefix, main_pid);
7492 else
7493 snprintf(logpath, sizeof(logpath), "%s.%d.%d", prefix, main_pid, thread->tid);
7494
7495 thread->logfile = fopen(logpath, "w");
7496
7497 if (thread->logfile == NULL)
7498 pg_fatal("could not open logfile \"%s\": %m", logpath);
7499 }
7500
7501 /* explicitly initialize the state machines */
7502 for (int i = 0; i < nstate; i++)
7504
7505 /* READY */
7507
7508 thread_start = pg_time_now();
7509 thread->started_time = thread_start;
7510 thread->conn_duration = 0;
7511 last_report = thread_start;
7512 next_report = last_report + (int64) 1000000 * progress;
7513
7514 /* STEADY */
7515 if (!is_connect)
7516 {
7517 /* make connections to the database before starting */
7518 for (int i = 0; i < nstate; i++)
7519 {
7520 if ((state[i].con = doConnect()) == NULL)
7521 {
7522 /* coldly abort on initial connection failure */
7523 pg_fatal("could not create connection for client %d",
7524 state[i].id);
7525 }
7526 }
7527 }
7528
7529 /* GO */
7531
7532 start = pg_time_now();
7533 thread->bench_start = start;
7534 thread->throttle_trigger = start;
7535
7536 /*
7537 * The log format currently has Unix epoch timestamps with whole numbers
7538 * of seconds. Round the first aggregate's start time down to the nearest
7539 * Unix epoch second (the very first aggregate might really have started a
7540 * fraction of a second later, but later aggregates are measured from the
7541 * whole number time that is actually logged).
7542 */
7543 initStats(&aggs, (start + epoch_shift) / 1000000 * 1000000);
7544 last = aggs;
7545
7546 /* loop till all clients have terminated */
7547 while (remains > 0)
7548 {
7549 int nsocks; /* number of sockets to be waited for */
7550 pg_time_usec_t min_usec;
7551 pg_time_usec_t now = 0; /* set this only if needed */
7552
7553 /*
7554 * identify which client sockets should be checked for input, and
7555 * compute the nearest time (if any) at which we need to wake up.
7556 */
7557 clear_socket_set(sockets);
7558 nsocks = 0;
7559 min_usec = PG_INT64_MAX;
7560 for (int i = 0; i < nstate; i++)
7561 {
7562 CState *st = &state[i];
7563
7564 if (st->state == CSTATE_SLEEP || st->state == CSTATE_THROTTLE)
7565 {
7566 /* a nap from the script, or under throttling */
7567 pg_time_usec_t this_usec;
7568
7569 /* get current time if needed */
7571
7572 /* min_usec should be the minimum delay across all clients */
7573 this_usec = (st->state == CSTATE_SLEEP ?
7574 st->sleep_until : st->txn_scheduled) - now;
7575 if (min_usec > this_usec)
7576 min_usec = this_usec;
7577 }
7578 else if (st->state == CSTATE_WAIT_RESULT ||
7580 {
7581 /*
7582 * waiting for result from server - nothing to do unless the
7583 * socket is readable
7584 */
7585 int sock = PQsocket(st->con);
7586
7587 if (sock < 0)
7588 {
7589 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7590 goto done;
7591 }
7592
7593 add_socket_to_set(sockets, sock, nsocks++);
7594 }
7595 else if (st->state != CSTATE_ABORTED &&
7596 st->state != CSTATE_FINISHED)
7597 {
7598 /*
7599 * This client thread is ready to do something, so we don't
7600 * want to wait. No need to examine additional clients.
7601 */
7602 min_usec = 0;
7603 break;
7604 }
7605 }
7606
7607 /* also wake up to print the next progress report on time */
7608 if (progress && min_usec > 0 && thread->tid == 0)
7609 {
7611
7612 if (now >= next_report)
7613 min_usec = 0;
7614 else if ((next_report - now) < min_usec)
7615 min_usec = next_report - now;
7616 }
7617
7618 /*
7619 * If no clients are ready to execute actions, sleep until we receive
7620 * data on some client socket or the timeout (if any) elapses.
7621 */
7622 if (min_usec > 0)
7623 {
7624 int rc = 0;
7625
7626 if (min_usec != PG_INT64_MAX)
7627 {
7628 if (nsocks > 0)
7629 {
7630 rc = wait_on_socket_set(sockets, min_usec);
7631 }
7632 else /* nothing active, simple sleep */
7633 {
7634 pg_usleep(min_usec);
7635 }
7636 }
7637 else /* no explicit delay, wait without timeout */
7638 {
7639 rc = wait_on_socket_set(sockets, 0);
7640 }
7641
7642 if (rc < 0)
7643 {
7644 if (errno == EINTR)
7645 {
7646 /* On EINTR, go back to top of loop */
7647 continue;
7648 }
7649 /* must be something wrong */
7650 pg_log_error("%s() failed: %m", SOCKET_WAIT_METHOD);
7651 goto done;
7652 }
7653 }
7654 else
7655 {
7656 /* min_usec <= 0, i.e. something needs to be executed now */
7657
7658 /* If we didn't wait, don't try to read any data */
7659 clear_socket_set(sockets);
7660 }
7661
7662 /* ok, advance the state machine of each connection */
7663 nsocks = 0;
7664 for (int i = 0; i < nstate; i++)
7665 {
7666 CState *st = &state[i];
7667
7668 if (st->state == CSTATE_WAIT_RESULT ||
7670 {
7671 /* don't call advanceConnectionState unless data is available */
7672 int sock = PQsocket(st->con);
7673
7674 if (sock < 0)
7675 {
7676 pg_log_error("invalid socket: %s", PQerrorMessage(st->con));
7677 goto done;
7678 }
7679
7680 if (!socket_has_input(sockets, sock, nsocks++))
7681 continue;
7682 }
7683 else if (st->state == CSTATE_FINISHED ||
7684 st->state == CSTATE_ABORTED)
7685 {
7686 /* this client is done, no need to consider it anymore */
7687 continue;
7688 }
7689
7690 advanceConnectionState(thread, st, &aggs);
7691
7692 /*
7693 * If --exit-on-abort is used, the program is going to exit when
7694 * any client is aborted.
7695 */
7696 if (exit_on_abort && st->state == CSTATE_ABORTED)
7697 goto done;
7698
7699 /*
7700 * If advanceConnectionState changed client to finished state,
7701 * that's one fewer client that remains.
7702 */
7703 else if (st->state == CSTATE_FINISHED ||
7704 st->state == CSTATE_ABORTED)
7705 remains--;
7706 }
7707
7708 /* progress report is made by thread 0 for all threads */
7709 if (progress && thread->tid == 0)
7710 {
7711 pg_time_usec_t now2 = pg_time_now();
7712
7713 if (now2 >= next_report)
7714 {
7715 /*
7716 * Horrible hack: this relies on the thread pointer we are
7717 * passed to be equivalent to threads[0], that is the first
7718 * entry of the threads array. That is why this MUST be done
7719 * by thread 0 and not any other.
7720 */
7721 printProgressReport(thread, thread_start, now2,
7722 &last, &last_report);
7723
7724 /*
7725 * Ensure that the next report is in the future, in case
7726 * pgbench/postgres got stuck somewhere.
7727 */
7728 do
7729 {
7730 next_report += (int64) 1000000 * progress;
7731 } while (now2 >= next_report);
7732 }
7733 }
7734 }
7735
7736done:
7737 if (exit_on_abort)
7738 {
7739 /*
7740 * Abort if any client is not finished, meaning some error occurred.
7741 */
7742 for (int i = 0; i < nstate; i++)
7743 {
7744 if (state[i].state != CSTATE_FINISHED)
7745 {
7746 pg_log_error("Run was aborted due to an error in thread %d",
7747 thread->tid);
7748 exit(2);
7749 }
7750 }
7751 }
7752
7753 disconnect_all(state, nstate);
7754
7755 if (thread->logfile)
7756 {
7757 if (agg_interval > 0)
7758 {
7759 /* log aggregated but not yet reported transactions */
7760 doLog(thread, state, &aggs, false, 0, 0);
7761 }
7762 fclose(thread->logfile);
7763 thread->logfile = NULL;
7764 }
7765 free_socket_set(sockets);
#define PG_INT64_MAX
Definition: c.h:598
int PQsocket(const PGconn *conn)
Definition: fe-connect.c:7705
#define MAXPGPATH
#define THREAD_BARRIER_WAIT(barrier)
Definition: pgbench.c:155
#define SOCKET_WAIT_METHOD
Definition: pgbench.c:107
static void free_socket_set(socket_set *sa)
Definition: pgbench.c:7940
static void clear_socket_set(socket_set *sa)
Definition: pgbench.c:7946
static void add_socket_to_set(socket_set *sa, int fd, int idx)
Definition: pgbench.c:7953
#define THREAD_FUNC_RETURN
Definition: pgbench.c:146
static void advanceConnectionState(TState *thread, CState *st, StatsData *agg)
Definition: pgbench.c:3630
static void printProgressReport(TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
Definition: pgbench.c:6268
static bool socket_has_input(socket_set *sa, int fd, int idx)
Definition: pgbench.c:7995
static int wait_on_socket_set(socket_set *sa, int64 usecs)
Definition: pgbench.c:7978
static socket_set * alloc_socket_set(int count)
Definition: pgbench.c:7934
void pg_usleep(long microsec)
Definition: signal.c:53
pg_time_usec_t started_time
Definition: pgbench.c:667
#define EINTR
Definition: win32_port.h:364

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

1544{
1545 PGresult *res;
1546
1547 res = PQexec(con, sql);
1548 if (PQresultStatus(res) != PGRES_COMMAND_OK)
1549 {
1550 pg_log_error("%s", PQerrorMessage(con));
1551 pg_log_error_detail("(ignoring this error and continuing anyway)");
1552 }
1553 PQclear(res);

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

Referenced by main().

◆ usage()

static void usage ( void  )
static

Definition at line 896 of file pgbench.c.

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

1766{
1767 const unsigned char *ptr = (const unsigned char *) name;
1768
1769 /* Mustn't be zero-length */
1770 if (*ptr == '\0')
1771 return false;
1772
1773 /* must not start with [0-9] */
1774 if (IS_HIGHBIT_SET(*ptr) ||
1775 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1776 "_", *ptr) != NULL)
1777 ptr++;
1778 else
1779 return false;
1780
1781 /* remaining characters can include [0-9] */
1782 while (*ptr)
1783 {
1784 if (IS_HIGHBIT_SET(*ptr) ||
1785 strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz"
1786 "_0123456789", *ptr) != NULL)
1787 ptr++;
1788 else
1789 return false;
1790 }
1791
1792 return true;

References IS_HIGHBIT_SET, and name.

Referenced by lookupCreateVariable().

◆ valueTruth()

static bool valueTruth ( PgBenchValue pval)
static

Definition at line 2050 of file pgbench.c.

2052{
2053 switch (pval->type)
2054 {
2055 case PGBT_NULL:
2056 return false;
2057 case PGBT_BOOLEAN:
2058 return pval->u.bval;
2059 case PGBT_INT:
2060 return pval->u.ival != 0;
2061 case PGBT_DOUBLE:
2062 return pval->u.dval != 0.0;
2063 default:
2064 /* internal error, unexpected type */
2065 Assert(0);
2066 return false;
2067 }

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

2010{
2011 if (pval->type == PGBT_NO_VALUE)
2012 return "none";
2013 else if (pval->type == PGBT_NULL)
2014 return "null";
2015 else if (pval->type == PGBT_INT)
2016 return "int";
2017 else if (pval->type == PGBT_DOUBLE)
2018 return "double";
2019 else if (pval->type == PGBT_BOOLEAN)
2020 return "boolean";
2021 else
2022 {
2023 /* internal error, should never get there */
2024 Assert(false);
2025 return NULL;
2026 }

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

7980{
7981 if (usecs > 0)
7982 {
7983 struct timeval timeout;
7984
7985 timeout.tv_sec = usecs / 1000000;
7986 timeout.tv_usec = usecs % 1000000;
7987 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, &timeout);
7988 }
7989 else
7990 {
7991 return select(sa->maxfd + 1, &sa->fds, NULL, NULL, NULL);
7992 }
#define select(n, r, w, e, timeout)
Definition: win32_port.h:503

References select.

Referenced by threadRun().

Variable Documentation

◆ agg_interval

int agg_interval
static

Definition at line 259 of file pgbench.c.

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

◆ barrier

◆ base_random_sequence

pg_prng_state base_random_sequence
static

Definition at line 478 of file pgbench.c.

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

◆ builtin_script

const BuiltinScript builtin_script[]
static

Definition at line 781 of file pgbench.c.

Referenced by findBuiltin(), and listAvailableScripts().

◆ dbName

const char* dbName = NULL
static

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

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

◆ exit_on_abort

bool exit_on_abort = false
static

Definition at line 771 of file pgbench.c.

Referenced by main(), and threadRun().

◆ failures_detailed

bool failures_detailed = false
static

Definition at line 292 of file pgbench.c.

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

◆ fillfactor

◆ index_tablespace

char* index_tablespace = NULL
static

Definition at line 218 of file pgbench.c.

Referenced by initCreatePKeys(), and main().

◆ is_connect

bool is_connect
static

Definition at line 266 of file pgbench.c.

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

◆ latency_limit

◆ logfile_prefix

char* logfile_prefix = NULL
static

Definition at line 299 of file pgbench.c.

Referenced by main(), and threadRun().

◆ main_pid

int main_pid
static

Definition at line 270 of file pgbench.c.

Referenced by main(), and threadRun().

◆ max_tries

uint32 max_tries = 1
static

◆ nclients

int nclients = 1
static

Definition at line 264 of file pgbench.c.

Referenced by main(), and printResults().

◆ nthreads

int nthreads = 1
static

Definition at line 265 of file pgbench.c.

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

◆ num_scripts

int num_scripts
static

Definition at line 766 of file pgbench.c.

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

◆ nxacts

int nxacts = 0
static

Definition at line 174 of file pgbench.c.

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

◆ partition_method

partition_method_t partition_method = PART_NONE
static

Definition at line 234 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 235 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 261 of file pgbench.c.

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

◆ pgbench_callbacks

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

Definition at line 847 of file pgbench.c.

Referenced by ParseScript().

◆ pghost

const char* pghost = NULL
static

Definition at line 295 of file pgbench.c.

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

◆ pgport

const char* pgport = NULL
static

Definition at line 296 of file pgbench.c.

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

◆ progname

const char* progname
static

Definition at line 300 of file pgbench.c.

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

◆ progress

◆ progress_timestamp

bool progress_timestamp = false
static

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

Referenced by main(), and printResults().

◆ random_seed

int64 random_seed = -1
static

Definition at line 238 of file pgbench.c.

Referenced by main(), and set_random_seed().

◆ report_per_command

bool report_per_command = false
static

Definition at line 267 of file pgbench.c.

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

◆ sample_rate

double sample_rate = 0.0
static

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

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

◆ total_weight

int64 total_weight = 0
static

Definition at line 767 of file pgbench.c.

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

◆ unlogged_tables

bool unlogged_tables = false
static

Definition at line 193 of file pgbench.c.

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

◆ use_log

bool use_log
static

Definition at line 257 of file pgbench.c.

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

◆ use_quiet

bool use_quiet
static

Definition at line 258 of file pgbench.c.

Referenced by initPopulateTable(), and main().

◆ username

const char* username = NULL
static

Definition at line 297 of file pgbench.c.

Referenced by doConnect(), and main().

◆ verbose_errors

bool verbose_errors = false
static

Definition at line 769 of file pgbench.c.

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