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

Go to the source code of this file.

Data Structures

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

Macros

#define POLL_USING_SELECT
 
#define M_PI   3.14159265358979323846
 
#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"
 
#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"
 
#define ERRCODE_UNDEFINED_TABLE   "42P01"
 
#define FNV_PRIME   UINT64CONST(0x100000001b3)
 
#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)
 
#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)
 
#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)
 
#define MM2_ROT   47
 
#define SOCKET_WAIT_METHOD   "select"
 
#define THREAD_T   pthread_t
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_CREATE(handle, function, arg)    pthread_create((handle), NULL, (function), (arg))
 
#define THREAD_JOIN(handle)    pthread_join((handle), NULL)
 
#define THREAD_BARRIER_T   pthread_barrier_t
 
#define THREAD_BARRIER_INIT(barrier, n)    pthread_barrier_init((barrier), NULL, (n))
 
#define THREAD_BARRIER_WAIT(barrier)   pthread_barrier_wait((barrier))
 
#define THREAD_BARRIER_DESTROY(barrier)   pthread_barrier_destroy((barrier))
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define VARIABLES_ALLOC_MARGIN   8
 
#define MAX_SCRIPTS   128 /* max number of SQL scripts allowed */
 
#define SHELL_COMMAND_SIZE   256 /* maximum size allowed for shell command */
 
#define SQL_COMMAND   1
 
#define META_COMMAND   2
 
#define MAX_ARGS   256
 
#define PG_TIME_GET_DOUBLE(t)   (0.000001 * (t))
 
#define PARAMS_ARRAY_SIZE   7
 
#define MAX_FARGS   16
 
#define COMMANDS_ALLOC_NUM   128
 

Typedefs

typedef struct socket_set socket_set
 
typedef struct SimpleStats SimpleStats
 
typedef int64 pg_time_usec_t
 
typedef struct StatsData StatsData
 
typedef enum EStatus EStatus
 
typedef enum TStatus TStatus
 
typedef enum MetaCommand MetaCommand
 
typedef enum QueryMode QueryMode
 
typedef struct Command Command
 
typedef struct ParsedScript ParsedScript
 
typedef struct BuiltinScript BuiltinScript
 
typedef void(* initRowMethod) (PQExpBufferData *sql, int64 curr)
 

Enumerations

enum  partition_method_t { PART_NONE , PART_RANGE , PART_HASH }
 
enum  EStatus {
  ESTATUS_NO_ERROR = 0 , ESTATUS_META_COMMAND_ERROR , ESTATUS_SERIALIZATION_ERROR , ESTATUS_DEADLOCK_ERROR ,
  ESTATUS_OTHER_SQL_ERROR
}
 
enum  TStatus { TSTATUS_IDLE , TSTATUS_IN_BLOCK , TSTATUS_CONN_ERROR , TSTATUS_OTHER_ERROR }
 
enum  ConnectionStateEnum {
  CSTATE_CHOOSE_SCRIPT , CSTATE_START_TX , CSTATE_PREPARE_THROTTLE , CSTATE_THROTTLE ,
  CSTATE_START_COMMAND , CSTATE_WAIT_RESULT , CSTATE_SLEEP , CSTATE_END_COMMAND ,
  CSTATE_SKIP_COMMAND , CSTATE_ERROR , CSTATE_WAIT_ROLLBACK_RESULT , CSTATE_RETRY ,
  CSTATE_FAILURE , CSTATE_END_TX , CSTATE_ABORTED , CSTATE_FINISHED
}
 
enum  MetaCommand {
  META_NONE , META_SET , META_SETSHELL , META_SHELL ,
  META_SLEEP , META_GSET , META_ASET , META_IF ,
  META_ELIF , META_ELSE , META_ENDIF , META_STARTPIPELINE ,
  META_SYNCPIPELINE , META_ENDPIPELINE
}
 
enum  QueryMode { QUERY_SIMPLE , QUERY_EXTENDED , QUERY_PREPARED , NUM_QUERYMODE }
 

Functions

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

Variables

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

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

Definition at line 163 of file pgbench.c.

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

◆ DEFAULT_INIT_STEPS

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

Definition at line 162 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 166 of file pgbench.c.

◆ ERRCODE_T_R_DEADLOCK_DETECTED

#define ERRCODE_T_R_DEADLOCK_DETECTED   "40P01"

Definition at line 77 of file pgbench.c.

◆ ERRCODE_T_R_SERIALIZATION_FAILURE

#define ERRCODE_T_R_SERIALIZATION_FAILURE   "40001"

Definition at line 76 of file pgbench.c.

◆ ERRCODE_UNDEFINED_TABLE

#define ERRCODE_UNDEFINED_TABLE   "42P01"

Definition at line 78 of file pgbench.c.

◆ FNV_OFFSET_BASIS

#define FNV_OFFSET_BASIS   UINT64CONST(0xcbf29ce484222325)

Definition at line 84 of file pgbench.c.

◆ FNV_PRIME

#define FNV_PRIME   UINT64CONST(0x100000001b3)

Definition at line 83 of file pgbench.c.

◆ LOG_STEP_SECONDS

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

Definition at line 165 of file pgbench.c.

◆ M_PI

#define M_PI   3.14159265358979323846

Definition at line 73 of file pgbench.c.

◆ MAX_ARGS

#define MAX_ARGS   256

Definition at line 685 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2242 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 347 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 171 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 679 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 168 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

Definition at line 170 of file pgbench.c.

◆ MM2_MUL

#define MM2_MUL   UINT64CONST(0xc6a4a7935bd1e995)

Definition at line 85 of file pgbench.c.

◆ MM2_MUL_TIMES_8

#define MM2_MUL_TIMES_8   UINT64CONST(0x35253c9ade8f4ca8)

Definition at line 86 of file pgbench.c.

◆ MM2_ROT

#define MM2_ROT   47

Definition at line 87 of file pgbench.c.

◆ naccounts

#define naccounts   100000

Definition at line 245 of file pgbench.c.

◆ nbranches

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

Definition at line 243 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 244 of file pgbench.c.

◆ PARAMS_ARRAY_SIZE

#define PARAMS_ARRAY_SIZE   7

◆ PG_TIME_GET_DOUBLE

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

Definition at line 867 of file pgbench.c.

◆ POLL_USING_SELECT

#define POLL_USING_SELECT

Definition at line 52 of file pgbench.c.

◆ SCALE_32BIT_THRESHOLD

#define SCALE_32BIT_THRESHOLD   20000

Definition at line 254 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

Definition at line 348 of file pgbench.c.

◆ SOCKET_WAIT_METHOD

#define SOCKET_WAIT_METHOD   "select"

Definition at line 106 of file pgbench.c.

◆ SQL_COMMAND

#define SQL_COMMAND   1

Definition at line 678 of file pgbench.c.

◆ THREAD_BARRIER_DESTROY

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

Definition at line 155 of file pgbench.c.

◆ THREAD_BARRIER_INIT

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

Definition at line 152 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   pthread_barrier_t

Definition at line 151 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

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

Definition at line 154 of file pgbench.c.

◆ THREAD_CREATE

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

Definition at line 147 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 146 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 145 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 144 of file pgbench.c.

◆ THREAD_JOIN

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

Definition at line 149 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   pthread_t

Definition at line 143 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 310 of file pgbench.c.

◆ WSEP

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

Definition at line 301 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ EStatus

typedef enum EStatus EStatus

◆ initRowMethod

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

Definition at line 843 of file pgbench.c.

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

Definition at line 370 of file pgbench.c.

◆ QueryMode

typedef enum QueryMode QueryMode

◆ SimpleStats

typedef struct SimpleStats SimpleStats

◆ socket_set

typedef struct socket_set socket_set

◆ StatsData

typedef struct StatsData StatsData

◆ TStatus

typedef enum TStatus TStatus

Enumeration Type Documentation

◆ ConnectionStateEnum

Enumerator
CSTATE_CHOOSE_SCRIPT 
CSTATE_START_TX 
CSTATE_PREPARE_THROTTLE 
CSTATE_THROTTLE 
CSTATE_START_COMMAND 
CSTATE_WAIT_RESULT 
CSTATE_SLEEP 
CSTATE_END_COMMAND 
CSTATE_SKIP_COMMAND 
CSTATE_ERROR 
CSTATE_WAIT_ROLLBACK_RESULT 
CSTATE_RETRY 
CSTATE_FAILURE 
CSTATE_END_TX 
CSTATE_ABORTED 
CSTATE_FINISHED 

Definition at line 485 of file pgbench.c.

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 454 of file pgbench.c.

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

◆ MetaCommand

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

Definition at line 687 of file pgbench.c.

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

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 226 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 705 of file pgbench.c.

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

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 468 of file pgbench.c.

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

Function Documentation

◆ accumStats()

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

Definition at line 1451 of file pgbench.c.

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

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

Referenced by doLog(), and processXactStats().

◆ add_socket_to_set()

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

Definition at line 7903 of file pgbench.c.

7905{
7906 /* See connect_slot() for background on this code. */
7907#ifdef WIN32
7908 if (sa->fds.fd_count + 1 >= FD_SETSIZE)
7909 {
7910 pg_log_error("too many concurrent database clients for this platform: %d",
7911 sa->fds.fd_count + 1);
7912 exit(1);
7913 }
7914#else
7915 if (fd < 0 || fd >= FD_SETSIZE)
7916 {
7917 pg_log_error("socket file descriptor out of range for select(): %d",
7918 fd);
7919 pg_log_error_hint("Try fewer concurrent database clients.");
7920 exit(1);
7921 }
7922#endif
7923 FD_SET(fd, &sa->fds);
7924 if (fd > sa->maxfd)
7925 sa->maxfd = fd;
exit(1)
#define pg_log_error(...)
Definition: logging.h:106
#define pg_log_error_hint(...)
Definition: logging.h:112
static int fd(const char *x, int i)
Definition: preproc-init.c:105

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

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6206 of file pgbench.c.

6208{
6209 if (script->commands == NULL || script->commands[0] == NULL)
6210 pg_fatal("empty command list for script \"%s\"", script->desc);
6211
6212 if (num_scripts >= MAX_SCRIPTS)
6213 pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6214
6215 CheckConditional(script);
6216
6217 sql_script[num_scripts] = *script;
6218 num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5868
#define MAX_SCRIPTS
Definition: pgbench.c:347
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:764
static int num_scripts
Definition: pgbench.c:765
const char * desc
Definition: pgbench.c:758
Command ** commands
Definition: pgbench.c:760

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

Referenced by ParseScript().

◆ addToSimpleStats()

static void addToSimpleStats ( SimpleStats ss,
double  val 
)
static

Definition at line 1403 of file pgbench.c.

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

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

Referenced by accumStats(), and advanceConnectionState().

◆ advanceConnectionState()

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

Definition at line 3589 of file pgbench.c.

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

References addToSimpleStats(), Assert, canRetryError(), chooseScript(), CState::cnt, CState::command, commandFailed(), ParsedScript::commands, CState::con, conditional_active(), conditional_stack_empty(), conditional_stack_peek(), conditional_stack_poke(), conditional_stack_pop(), conditional_stack_push(), conditional_stack_reset(), TState::conn_duration, CState::cs_func_rs, CState::cstack, CSTATE_ABORTED, CSTATE_CHOOSE_SCRIPT, CSTATE_END_COMMAND, CSTATE_END_TX, CSTATE_ERROR, CSTATE_FAILURE, CSTATE_FINISHED, CSTATE_PREPARE_THROTTLE, CSTATE_RETRY, CSTATE_SKIP_COMMAND, CSTATE_SLEEP, CSTATE_START_COMMAND, CSTATE_START_TX, CSTATE_THROTTLE, CSTATE_WAIT_RESULT, CSTATE_WAIT_ROLLBACK_RESULT, ParsedScript::desc, discardUntilSync(), doConnect(), doRetry(), duration, end_time, CState::estatus, ESTATUS_META_COMMAND_ERROR, ESTATUS_NO_ERROR, executeMetaCommand(), Command::failures, finishCon(), getPoissonRand(), getTransactionStatus(), CState::id, IFSTATE_ELSE_FALSE, IFSTATE_ELSE_TRUE, IFSTATE_FALSE, IFSTATE_IGNORED, IFSTATE_NONE, IFSTATE_TRUE, is_connect, latency_limit, Command::meta, META_ASET, META_COMMAND, META_ELIF, META_ELSE, META_ENDIF, META_GSET, META_IF, now(), nxacts, pg_free(), pg_log_debug, pg_log_error, PG_TIME_GET_DOUBLE, pg_time_now(), pg_time_now_lazy(), PGRES_COMMAND_OK, PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQclear(), PQconsumeInput(), PQerrorMessage(), PQgetResult(), PQisBusy(), PQpipelineStatus(), PQresultStatus(), PQsendQuery(), CState::prepared, printVerboseErrorMessages(), processXactStats(), CState::random_state, readCommandResponse(), report_per_command, res, Command::retries, sendCommand(), SQL_COMMAND, sql_script, start, CState::state, Command::stats, CState::stmt_begin, throttle_delay, TState::throttle_trigger, timer_exceeded, CState::tries, TState::ts_throttle_rs, TSTATUS_CONN_ERROR, TSTATUS_IDLE, TSTATUS_IN_BLOCK, CState::txn_begin, CState::txn_scheduled, Command::type, CState::use_file, Command::varprefix, and verbose_errors.

Referenced by threadRun().

◆ alloc_socket_set()

static socket_set * alloc_socket_set ( int  count)
static

Definition at line 7884 of file pgbench.c.

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

References pg_malloc0().

Referenced by threadRun().

◆ allocCStatePrepared()

static void allocCStatePrepared ( CState st)
static

Definition at line 3069 of file pgbench.c.

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

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

Referenced by prepareCommand(), and prepareCommandsInPipeline().

◆ assignVariables()

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

Definition at line 1936 of file pgbench.c.

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

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3225 of file pgbench.c.

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

References ESTATUS_DEADLOCK_ERROR, and ESTATUS_SERIALIZATION_ERROR.

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

◆ CheckConditional()

static void CheckConditional ( const ParsedScript ps)
static

Definition at line 5868 of file pgbench.c.

5870{
5871 /* statically check conditional structure */
5873 int i;
5874
5875 for (i = 0; ps->commands[i] != NULL; i++)
5876 {
5877 Command *cmd = ps->commands[i];
5878
5879 if (cmd->type == META_COMMAND)
5880 {
5881 switch (cmd->meta)
5882 {
5883 case META_IF:
5885 break;
5886 case META_ELIF:
5888 ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5890 ConditionError(ps->desc, i + 1, "\\elif after \\else");
5891 break;
5892 case META_ELSE:
5894 ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5896 ConditionError(ps->desc, i + 1, "\\else after \\else");
5898 break;
5899 case META_ENDIF:
5900 if (!conditional_stack_pop(cs))
5901 ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5902 break;
5903 default:
5904 /* ignore anything else... */
5905 break;
5906 }
5907 }
5908 }
5909 if (!conditional_stack_empty(cs))
5910 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:5858

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

5218{
5219 if (initialize_steps[0] == '\0')
5220 pg_fatal("no initialization steps specified");
5221
5222 for (const char *step = initialize_steps; *step != '\0'; step++)
5223 {
5224 if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5225 {
5226 pg_log_error("unrecognized initialization step \"%c\"", *step);
5227 pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5228 exit(1);
5229 }
5230 }
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:163

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

Referenced by main().

◆ chooseScript()

static int chooseScript ( TState thread)
static

Definition at line 3047 of file pgbench.c.

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

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

Referenced by advanceConnectionState().

◆ clear_socket_set()

static void clear_socket_set ( socket_set sa)
static

Definition at line 7896 of file pgbench.c.

7898{
7899 FD_ZERO(&sa->fds);
7900 sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

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

Definition at line 2004 of file pgbench.c.

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

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

Referenced by evalLazyFunc(), and evalStandardFunc().

◆ coerceToDouble()

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

Definition at line 2073 of file pgbench.c.

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

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

Referenced by evalStandardFunc().

◆ coerceToInt()

static bool coerceToInt ( PgBenchValue pval,
int64 ival 
)
static

Definition at line 2045 of file pgbench.c.

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

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

Referenced by evalStandardFunc().

◆ commandError()

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

Definition at line 3038 of file pgbench.c.

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

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

Referenced by readCommandResponse().

◆ commandFailed()

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

Definition at line 3028 of file pgbench.c.

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

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

Referenced by advanceConnectionState(), and executeMetaCommand().

◆ compareVariableNames()

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

Definition at line 1596 of file pgbench.c.

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

References name.

Referenced by lookupVariable().

◆ computeIterativeZipfian()

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

Definition at line 1201 of file pgbench.c.

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

5860{
5861 pg_fatal("condition error in script \"%s\" command %d: %s",
5862 desc, cmdn, msg);

References pg_fatal.

Referenced by CheckConditional().

◆ create_sql_command()

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

Definition at line 5562 of file pgbench.c.

5564{
5565 Command *my_command;
5566 char *p = skip_sql_comments(buf->data);
5567
5568 if (p == NULL)
5569 return NULL;
5570
5571 /* Allocate and initialize Command structure */
5572 my_command = (Command *) pg_malloc(sizeof(Command));
5573 initPQExpBuffer(&my_command->lines);
5574 appendPQExpBufferStr(&my_command->lines, p);
5575 my_command->first_line = NULL; /* this is set later */
5576 my_command->type = SQL_COMMAND;
5577 my_command->meta = META_NONE;
5578 my_command->argc = 0;
5579 my_command->retries = 0;
5580 my_command->failures = 0;
5581 memset(my_command->argv, 0, sizeof(my_command->argv));
5582 my_command->varprefix = NULL; /* allocated later, if needed */
5583 my_command->expr = NULL;
5584 initSimpleStats(&my_command->stats);
5585 my_command->prepname = NULL; /* set later, if needed */
5586
5587 return my_command;
static char * buf
Definition: pg_test_fsync.c:72
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5527
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1394
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:742
PgBenchExpr * expr
Definition: pgbench.c:750
char * argv[MAX_ARGS]
Definition: pgbench.c:747
char * first_line
Definition: pgbench.c:743
int argc
Definition: pgbench.c:746
char * prepname
Definition: pgbench.c:748

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

Referenced by ParseScript().

◆ createPartitions()

static void createPartitions ( PGconn con)
static

Definition at line 4741 of file pgbench.c.

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

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

Referenced by initCreateTables().

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3474 of file pgbench.c.

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

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

Referenced by advanceConnectionState().

◆ disconnect_all()

static void disconnect_all ( CState state,
int  length 
)
static

Definition at line 4707 of file pgbench.c.

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

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn * doConnect ( void  )
static

Definition at line 1531 of file pgbench.c.

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

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

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

References accumStats(), agg_interval, Assert, StatsData::cnt, CState::cnt, StatsData::deadlock_failures, epoch_shift, CState::estatus, ESTATUS_NO_ERROR, failures_detailed, fprintf, getResultString(), CState::id, initStats(), INT64_FORMAT, 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 3428 of file pgbench.c.

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

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

Referenced by advanceConnectionState().

◆ enlargeVariables()

static void enlargeVariables ( Variables variables,
int  needed 
)
static

Definition at line 1773 of file pgbench.c.

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

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

Referenced by lookupCreateVariable().

◆ evalFunc()

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

Definition at line 2821 of file pgbench.c.

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

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

Referenced by evaluateExpr().

◆ evalLazyFunc()

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

Definition at line 2132 of file pgbench.c.

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

References a1, a2, generate_unaccent_rules::args, Assert, coerceToBool(), 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 2249 of file pgbench.c.

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

References generate_unaccent_rules::args, Assert, b, PgBenchValue::bval, coerceToBool(), coerceToDouble(), coerceToInt(), CState::command, CState::cs_func_rs, PgBenchValue::dval, evaluateExpr(), PgBenchExprLink::expr, fprintf, getExponentialRand(), getGaussianRand(), getHashFnv1a(), getHashMurmur2(), getrand(), getZipfianRand(), i, INT64_FORMAT, PgBenchValue::ival, M_PI, Max, MAX_FARGS, MAX_ZIPFIAN_PARAM, Min, MIN_GAUSSIAN_PARAM, MIN_ZIPFIAN_PARAM, PgBenchExprLink::next, permute(), pg_add_s64_overflow(), PG_INT64_MIN, pg_log_error, pg_mul_s64_overflow(), pg_sub_s64_overflow(), PGBENCH_ABS, PGBENCH_ADD, PGBENCH_BITAND, PGBENCH_BITOR, PGBENCH_BITXOR, PGBENCH_DEBUG, PGBENCH_DIV, PGBENCH_DOUBLE, PGBENCH_EQ, PGBENCH_EXP, PGBENCH_GREATEST, PGBENCH_HASH_FNV1A, PGBENCH_HASH_MURMUR2, PGBENCH_INT, PGBENCH_IS, PGBENCH_LE, PGBENCH_LEAST, PGBENCH_LN, PGBENCH_LSHIFT, PGBENCH_LT, PGBENCH_MOD, PGBENCH_MUL, PGBENCH_NE, PGBENCH_NOT, PGBENCH_PERMUTE, PGBENCH_PI, PGBENCH_POW, PGBENCH_RANDOM, PGBENCH_RANDOM_EXPONENTIAL, PGBENCH_RANDOM_GAUSSIAN, PGBENCH_RANDOM_ZIPFIAN, PGBENCH_RSHIFT, PGBENCH_SQRT, PGBENCH_SUB, PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NULL, res, setBoolValue(), setDoubleValue(), setIntValue(), setNullValue(), size, type, PgBenchValue::type, PgBenchValue::u, unlikely, CState::use_file, and val.

Referenced by evalFunc().

◆ evaluateExpr()

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

Definition at line 2837 of file pgbench.c.

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

References PgBenchExpr::constant, ENODE_CONSTANT, ENODE_FUNCTION, ENODE_VARIABLE, PgBenchExpr::etype, evalFunc(), PgBenchExpr::function, lookupVariable(), makeVariableValue(), pg_fatal, pg_log_error, PgBenchExpr::u, Variable::value, PgBenchExpr::variable, 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 3383 of file pgbench.c.

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

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

Referenced by executeMetaCommand().

◆ executeMetaCommand()

static ConnectionStateEnum executeMetaCommand ( CState st,
pg_time_usec_t now 
)
static

Definition at line 4287 of file pgbench.c.

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

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

Referenced by advanceConnectionState().

◆ executeStatement()

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

Definition at line 1500 of file pgbench.c.

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

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

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

◆ findBuiltin()

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

Definition at line 6133 of file pgbench.c.

6135{
6136 int i,
6137 found = 0,
6138 len = strlen(name);
6139 const BuiltinScript *result = NULL;
6140
6141 for (i = 0; i < lengthof(builtin_script); i++)
6142 {
6143 if (strncmp(builtin_script[i].name, name, len) == 0)
6144 {
6145 result = &builtin_script[i];
6146 found++;
6147 }
6148 }
6149
6150 /* ok, unambiguous result */
6151 if (found == 1)
6152 return result;
6153
6154 /* error cases */
6155 if (found == 0)
6156 pg_log_error("no builtin script found for name \"%s\"", name);
6157 else /* found > 1 */
6158 pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6159
6161 exit(1);
#define lengthof(array)
Definition: c.h:745
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6121
static const BuiltinScript builtin_script[]
Definition: pgbench.c:780

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

Referenced by main().

◆ finishCon()

static void finishCon ( CState st)
static

Definition at line 7719 of file pgbench.c.

7721{
7722 if (st->con != NULL)
7723 {
7724 PQfinish(st->con);
7725 st->con = NULL;
7726 }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5591 of file pgbench.c.

5593{
5594 termPQExpBuffer(&command->lines);
5595 pg_free(command->first_line);
5596 for (int i = 0; i < command->argc; i++)
5597 pg_free(command->argv[i]);
5598 pg_free(command->varprefix);
5599
5600 /*
5601 * It should also free expr recursively, but this is currently not needed
5602 * as only gset commands (which do not have an expression) are freed.
5603 */
5604 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 7890 of file pgbench.c.

7892{
7893 pg_free(sa);

References pg_free().

Referenced by threadRun().

◆ getExponentialRand()

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

Definition at line 1113 of file pgbench.c.

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

References Assert, and pg_prng_double().

Referenced by evalStandardFunc().

◆ getFailures()

static int64 getFailures ( const StatsData stats)
static

Definition at line 4506 of file pgbench.c.

4508{
4509 return (stats->serialization_failures +
4510 stats->deadlock_failures);

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

Referenced by printProgressReport(), and printResults().

◆ getGaussianRand()

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

Definition at line 1137 of file pgbench.c.

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

References Assert, MIN_GAUSSIAN_PARAM, and pg_prng_double_normal().

Referenced by evalStandardFunc().

◆ getHashFnv1a()

static int64 getHashFnv1a ( int64  val,
uint64  seed 
)
static

Definition at line 1245 of file pgbench.c.

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

References FNV_OFFSET_BASIS, FNV_PRIME, i, and val.

Referenced by evalStandardFunc().

◆ getHashMurmur2()

static int64 getHashMurmur2 ( int64  val,
uint64  seed 
)
static

Definition at line 1270 of file pgbench.c.

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

References MM2_MUL, MM2_MUL_TIMES_8, MM2_ROT, and val.

Referenced by evalStandardFunc().

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2880 of file pgbench.c.

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

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

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1179 of file pgbench.c.

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

References pg_prng_double().

Referenced by advanceConnectionState().

◆ getQueryParams()

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

Definition at line 1972 of file pgbench.c.

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

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

Referenced by sendCommand().

◆ getrand()

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

Definition at line 1102 of file pgbench.c.

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

References pg_prng_uint64_range().

Referenced by chooseScript(), and evalStandardFunc().

◆ getResultString()

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

Definition at line 4517 of file pgbench.c.

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

References ESTATUS_DEADLOCK_ERROR, ESTATUS_SERIALIZATION_ERROR, failures_detailed, and pg_fatal.

Referenced by doLog().

◆ getSQLErrorStatus()

static EStatus getSQLErrorStatus ( const char *  sqlState)
static

Definition at line 3208 of file pgbench.c.

3210{
3211 if (sqlState != NULL)
3212 {
3213 if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3215 else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3217 }
3218
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:77
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76

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

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5321 of file pgbench.c.

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

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

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3514 of file pgbench.c.

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

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

Referenced by advanceConnectionState().

◆ getVariable()

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

Definition at line 1631 of file pgbench.c.

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

References Assert, PgBenchValue::bval, PgBenchValue::dval, INT64_FORMAT, PgBenchValue::ival, lookupVariable(), name, pg_strdup(), PGBT_BOOLEAN, PGBT_DOUBLE, PGBT_INT, PGBT_NO_VALUE, PGBT_NULL, snprintf, Variable::svalue, PgBenchValue::type, PgBenchValue::u, and Variable::value.

Referenced by assignVariables(), evaluateSleep(), getQueryParams(), and runShellCommand().

◆ getZipfianRand()

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

Definition at line 1231 of file pgbench.c.

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

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

Referenced by evalStandardFunc().

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 7735 of file pgbench.c.

7737{
7738 timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initAccount()

static void initAccount ( PQExpBufferData sql,
int64  curr 
)
static

Definition at line 4933 of file pgbench.c.

4935{
4936 /* "filler" column defaults to blank padded empty string */
4938 INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n",
4939 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 4915 of file pgbench.c.

4917{
4918 /* "filler" column uses NULL */
4920 INT64_FORMAT "\t0\t\\N\n",
4921 curr + 1);

References INT64_FORMAT, and printfPQExpBuffer().

Referenced by initGenerateDataClientSide().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5190 of file pgbench.c.

5192{
5193 static const char *const DDLKEYs[] = {
5194 "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5195 "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5196 "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5197 "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5198 "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5199 };
5200 int i;
5201
5202 fprintf(stderr, "creating foreign keys...\n");
5203 for (i = 0; i < lengthof(DDLKEYs); i++)
5204 {
5205 executeStatement(con, DDLKEYs[i]);
5206 }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5152 of file pgbench.c.

5154{
5155 static const char *const DDLINDEXes[] = {
5156 "alter table pgbench_branches add primary key (bid)",
5157 "alter table pgbench_tellers add primary key (tid)",
5158 "alter table pgbench_accounts add primary key (aid)"
5159 };
5160 int i;
5161 PQExpBufferData query;
5162
5163 fprintf(stderr, "creating primary keys...\n");
5164 initPQExpBuffer(&query);
5165
5166 for (i = 0; i < lengthof(DDLINDEXes); i++)
5167 {
5168 resetPQExpBuffer(&query);
5169 appendPQExpBufferStr(&query, DDLINDEXes[i]);
5170
5171 if (index_tablespace != NULL)
5172 {
5173 char *escape_tablespace;
5174
5175 escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5176 strlen(index_tablespace));
5177 appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5178 PQfreemem(escape_tablespace);
5179 }
5180
5181 executeStatement(con, query.data);
5182 }
5183
5184 termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:4032
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4310
static char * index_tablespace
Definition: pgbench.c:217
void resetPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:146

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

Referenced by runInitSteps().

◆ initCreateTables()

static void initCreateTables ( PGconn con)
static

Definition at line 4810 of file pgbench.c.

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

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

Referenced by runInitSteps().

◆ initDropTables()

static void initDropTables ( PGconn con)
static

Definition at line 4719 of file pgbench.c.

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

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 5062 of file pgbench.c.

5064{
5065 fprintf(stderr, "generating data (client-side)...\n");
5066
5067 /*
5068 * we do all of this in one transaction to enable the backend's
5069 * data-loading optimizations
5070 */
5071 executeStatement(con, "begin");
5072
5073 /* truncate away any old data */
5074 initTruncateTables(con);
5075
5076 /*
5077 * fill branches, tellers, accounts in that order in case foreign keys
5078 * already exist
5079 */
5080 initPopulateTable(con, "pgbench_branches", nbranches, initBranch);
5081 initPopulateTable(con, "pgbench_tellers", ntellers, initTeller);
5082 initPopulateTable(con, "pgbench_accounts", naccounts, initAccount);
5083
5084 executeStatement(con, "commit");
static void initTeller(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4924
static void initBranch(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4915
#define ntellers
Definition: pgbench.c:244
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4905
static void initAccount(PQExpBufferData *sql, int64 curr)
Definition: pgbench.c:4933
#define nbranches
Definition: pgbench.c:243
static void initPopulateTable(PGconn *con, const char *table, int64 base, initRowMethod init_row)
Definition: pgbench.c:4942

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

5096{
5097 PQExpBufferData sql;
5098
5099 fprintf(stderr, "generating data (server-side)...\n");
5100
5101 /*
5102 * we do all of this in one transaction to enable the backend's
5103 * data-loading optimizations
5104 */
5105 executeStatement(con, "begin");
5106
5107 /* truncate away any old data */
5108 initTruncateTables(con);
5109
5110 initPQExpBuffer(&sql);
5111
5112 printfPQExpBuffer(&sql,
5113 "insert into pgbench_branches(bid,bbalance) "
5114 "select bid, 0 "
5115 "from generate_series(1, %d) as bid", nbranches * scale);
5116 executeStatement(con, sql.data);
5117
5118 printfPQExpBuffer(&sql,
5119 "insert into pgbench_tellers(tid,bid,tbalance) "
5120 "select tid, (tid - 1) / %d + 1, 0 "
5121 "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5122 executeStatement(con, sql.data);
5123
5124 printfPQExpBuffer(&sql,
5125 "insert into pgbench_accounts(aid,bid,abalance,filler) "
5126 "select aid, (aid - 1) / %d + 1, 0, '' "
5127 "from generate_series(1, " INT64_FORMAT ") as aid",
5129 executeStatement(con, sql.data);
5130
5131 termPQExpBuffer(&sql);
5132
5133 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 4942 of file pgbench.c.

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

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

Referenced by initGenerateDataClientSide().

◆ initRandomState()

static void initRandomState ( pg_prng_state state)
static

Definition at line 1088 of file pgbench.c.

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

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

Referenced by main().

◆ initSimpleStats()

static void initSimpleStats ( SimpleStats ss)
static

Definition at line 1394 of file pgbench.c.

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

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

◆ initStats()

static void initStats ( StatsData sd,
pg_time_usec_t  start 
)
static

Definition at line 1434 of file pgbench.c.

1436{
1437 sd->start_time = start;
1438 sd->cnt = 0;
1439 sd->skipped = 0;
1440 sd->retries = 0;
1441 sd->retried = 0;
1442 sd->serialization_failures = 0;
1443 sd->deadlock_failures = 0;
1445 initSimpleStats(&sd->lag);

References Stats