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 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   void *
 
#define THREAD_FUNC_RETURN_TYPE   void *
 
#define THREAD_FUNC_RETURN   return NULL
 
#define THREAD_FUNC_CC
 
#define THREAD_BARRIER_T   int
 
#define THREAD_BARRIER_INIT(barrier, n)   (*(barrier) = 0)
 
#define THREAD_BARRIER_WAIT(barrier)
 
#define THREAD_BARRIER_DESTROY(barrier)
 
#define DEFAULT_INIT_STEPS   "dtgvp" /* default -I setting */
 
#define ALL_INIT_STEPS   "dtgGvpf" /* all possible steps */
 
#define LOG_STEP_SECONDS   5 /* seconds between log messages */
 
#define DEFAULT_NXACTS   10 /* default nxacts */
 
#define MIN_GAUSSIAN_PARAM   2.0 /* minimum parameter for gauss */
 
#define MIN_ZIPFIAN_PARAM   1.001 /* minimum parameter for zipfian */
 
#define MAX_ZIPFIAN_PARAM   1000.0 /* maximum parameter for zipfian */
 
#define nbranches
 
#define ntellers   10
 
#define naccounts   100000
 
#define SCALE_32BIT_THRESHOLD   20000
 
#define WSEP   '@' /* weight separator */
 
#define 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
 

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_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 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 initGenerateDataClientSide (PGconn *con)
 
static void initGenerateDataServerSide (PGconn *con)
 
static void initVacuum (PGconn *con)
 
static void initCreatePKeys (PGconn *con)
 
static void initCreateFKeys (PGconn *con)
 
static void checkInitSteps (const char *initialize_steps)
 
static void runInitSteps (const char *initialize_steps)
 
static void GetTableInfo (PGconn *con, bool scale_given)
 
static bool parseQuery (Command *cmd)
 
void syntax_error (const char *source, int lineno, const char *line, const char *command, const char *msg, const char *more, int column)
 
static char * skip_sql_comments (char *sql_command)
 
static Commandcreate_sql_command (PQExpBuffer buf, const char *source)
 
static void free_command (Command *command)
 
static void postprocess_sql_command (Command *my_command)
 
static Commandprocess_backslash_command (PsqlScanState sstate, const char *source)
 
static void ConditionError (const char *desc, int cmdn, const char *msg)
 
static void CheckConditional (const ParsedScript *ps)
 
static void ParseScript (const char *script, const char *desc, int weight)
 
static char * read_file_contents (FILE *fd)
 
static void process_file (const char *filename, int weight)
 
static void process_builtin (const BuiltinScript *bi, int weight)
 
static void listAvailableScripts (void)
 
static const BuiltinScriptfindBuiltin (const char *name)
 
static int parseScriptWeight (const char *option, char **script)
 
static void printProgressReport (TState *threads, int64 test_start, pg_time_usec_t now, StatsData *last, int64 *last_report)
 
static void printSimpleStats (const char *prefix, SimpleStats *ss)
 
static void printVersion (PGconn *con)
 
static void printResults (StatsData *total, pg_time_usec_t total_duration, pg_time_usec_t conn_total_duration, pg_time_usec_t conn_elapsed_duration, int64 latency_late)
 
static bool set_random_seed (const char *seed)
 
int main (int argc, char **argv)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 

Variables

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

Macro Definition Documentation

◆ ALL_INIT_STEPS

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

Definition at line 173 of file pgbench.c.

◆ COMMANDS_ALLOC_NUM

#define COMMANDS_ALLOC_NUM   128

◆ DEFAULT_INIT_STEPS

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

Definition at line 172 of file pgbench.c.

◆ DEFAULT_NXACTS

#define DEFAULT_NXACTS   10 /* default nxacts */

Definition at line 176 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 175 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 693 of file pgbench.c.

◆ MAX_FARGS

#define MAX_FARGS   16

Definition at line 2236 of file pgbench.c.

◆ MAX_SCRIPTS

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

Definition at line 356 of file pgbench.c.

◆ MAX_ZIPFIAN_PARAM

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

Definition at line 181 of file pgbench.c.

◆ META_COMMAND

#define META_COMMAND   2

Definition at line 687 of file pgbench.c.

◆ MIN_GAUSSIAN_PARAM

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

Definition at line 178 of file pgbench.c.

◆ MIN_ZIPFIAN_PARAM

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

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

◆ nbranches

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

Definition at line 253 of file pgbench.c.

◆ ntellers

#define ntellers   10

Definition at line 254 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 870 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 264 of file pgbench.c.

◆ SHELL_COMMAND_SIZE

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

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

◆ THREAD_BARRIER_DESTROY

#define THREAD_BARRIER_DESTROY (   barrier)

Definition at line 165 of file pgbench.c.

◆ THREAD_BARRIER_INIT

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

Definition at line 163 of file pgbench.c.

◆ THREAD_BARRIER_T

#define THREAD_BARRIER_T   int

Definition at line 162 of file pgbench.c.

◆ THREAD_BARRIER_WAIT

#define THREAD_BARRIER_WAIT (   barrier)

Definition at line 164 of file pgbench.c.

◆ THREAD_FUNC_CC

#define THREAD_FUNC_CC

Definition at line 161 of file pgbench.c.

◆ THREAD_FUNC_RETURN

#define THREAD_FUNC_RETURN   return NULL

Definition at line 160 of file pgbench.c.

◆ THREAD_FUNC_RETURN_TYPE

#define THREAD_FUNC_RETURN_TYPE   void *

Definition at line 159 of file pgbench.c.

◆ THREAD_T

#define THREAD_T   void *

Definition at line 158 of file pgbench.c.

◆ VARIABLES_ALLOC_MARGIN

#define VARIABLES_ALLOC_MARGIN   8

Definition at line 319 of file pgbench.c.

◆ WSEP

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

Definition at line 311 of file pgbench.c.

Typedef Documentation

◆ BuiltinScript

typedef struct BuiltinScript BuiltinScript

◆ Command

typedef struct Command Command

◆ EStatus

typedef enum EStatus EStatus

◆ MetaCommand

typedef enum MetaCommand MetaCommand

◆ ParsedScript

typedef struct ParsedScript ParsedScript

◆ pg_time_usec_t

typedef int64 pg_time_usec_t

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

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

◆ EStatus

enum EStatus
Enumerator
ESTATUS_NO_ERROR 
ESTATUS_META_COMMAND_ERROR 
ESTATUS_SERIALIZATION_ERROR 
ESTATUS_DEADLOCK_ERROR 
ESTATUS_OTHER_SQL_ERROR 

Definition at line 463 of file pgbench.c.

465 {
466  ESTATUS_NO_ERROR = 0,
468 
469  /* SQL errors */
@ ESTATUS_DEADLOCK_ERROR
Definition: pgbench.c:470
@ ESTATUS_META_COMMAND_ERROR
Definition: pgbench.c:466
@ ESTATUS_OTHER_SQL_ERROR
Definition: pgbench.c:471
@ ESTATUS_NO_ERROR
Definition: pgbench.c:465
@ ESTATUS_SERIALIZATION_ERROR
Definition: pgbench.c:469

◆ MetaCommand

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

Definition at line 695 of file pgbench.c.

697 {
698  META_NONE, /* not a known meta-command */
699  META_SET, /* \set */
700  META_SETSHELL, /* \setshell */
701  META_SHELL, /* \shell */
702  META_SLEEP, /* \sleep */
703  META_GSET, /* \gset */
704  META_ASET, /* \aset */
705  META_IF, /* \if */
706  META_ELIF, /* \elif */
707  META_ELSE, /* \else */
708  META_ENDIF, /* \endif */
709  META_STARTPIPELINE, /* \startpipeline */
710  META_ENDPIPELINE /* \endpipeline */
@ META_ELSE
Definition: pgbench.c:706
@ META_SETSHELL
Definition: pgbench.c:699
@ META_ENDIF
Definition: pgbench.c:707
@ META_SHELL
Definition: pgbench.c:700
@ META_STARTPIPELINE
Definition: pgbench.c:708
@ META_SET
Definition: pgbench.c:698
@ META_ELIF
Definition: pgbench.c:705
@ META_SLEEP
Definition: pgbench.c:701
@ META_NONE
Definition: pgbench.c:697
@ META_IF
Definition: pgbench.c:704
@ META_ENDPIPELINE
Definition: pgbench.c:709
@ META_ASET
Definition: pgbench.c:703
@ META_GSET
Definition: pgbench.c:702

◆ partition_method_t

Enumerator
PART_NONE 
PART_RANGE 
PART_HASH 

Definition at line 236 of file pgbench.c.

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

◆ QueryMode

enum QueryMode
Enumerator
QUERY_SIMPLE 
QUERY_EXTENDED 
QUERY_PREPARED 
NUM_QUERYMODE 

Definition at line 712 of file pgbench.c.

714 {
715  QUERY_SIMPLE, /* simple query */
716  QUERY_EXTENDED, /* extended query */
717  QUERY_PREPARED, /* extended query with prepared statements */
@ QUERY_PREPARED
Definition: pgbench.c:716
@ NUM_QUERYMODE
Definition: pgbench.c:717
@ QUERY_SIMPLE
Definition: pgbench.c:714
@ QUERY_EXTENDED
Definition: pgbench.c:715

◆ TStatus

enum TStatus
Enumerator
TSTATUS_IDLE 
TSTATUS_IN_BLOCK 
TSTATUS_CONN_ERROR 
TSTATUS_OTHER_ERROR 

Definition at line 477 of file pgbench.c.

479 {
480  TSTATUS_IDLE,
@ TSTATUS_CONN_ERROR
Definition: pgbench.c:481
@ TSTATUS_IDLE
Definition: pgbench.c:479
@ TSTATUS_IN_BLOCK
Definition: pgbench.c:480
@ TSTATUS_OTHER_ERROR
Definition: pgbench.c:482

Function Documentation

◆ accumStats()

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

Definition at line 1445 of file pgbench.c.

1448 {
1449  /* Record the skipped transaction */
1450  if (skipped)
1451  {
1452  /* no latency to record on skipped transactions */
1453  stats->skipped++;
1454  return;
1455  }
1456 
1457  /*
1458  * Record the number of retries regardless of whether the transaction was
1459  * successful or failed.
1460  */
1461  if (tries > 1)
1462  {
1463  stats->retries += (tries - 1);
1464  stats->retried++;
1465  }
1466 
1467  switch (estatus)
1468  {
1469  /* Record the successful transaction */
1470  case ESTATUS_NO_ERROR:
1471  stats->cnt++;
1472 
1473  addToSimpleStats(&stats->latency, lat);
1474 
1475  /* and possibly the same for schedule lag */
1476  if (throttle_delay)
1477  addToSimpleStats(&stats->lag, lag);
1478  break;
1479 
1480  /* Record the failed transaction */
1482  stats->serialization_failures++;
1483  break;
1485  stats->deadlock_failures++;
1486  break;
1487  default:
1488  /* internal error which should never occur */
1489  pg_fatal("unexpected error status: %d", estatus);
1490  }
#define pg_fatal(...)
double throttle_delay
Definition: pgbench.c:213
static void addToSimpleStats(SimpleStats *ss, double val)
Definition: pgbench.c:1397
int64 serialization_failures
Definition: pgbench.c:444
int64 cnt
Definition: pgbench.c:434
int64 retried
Definition: pgbench.c:440
int64 deadlock_failures
Definition: pgbench.c:447
int64 skipped
Definition: pgbench.c:436
SimpleStats lag
Definition: pgbench.c:451
int64 retries
Definition: pgbench.c:438
SimpleStats latency
Definition: pgbench.c:450

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

7776 {
7777  if (fd < 0 || fd >= FD_SETSIZE)
7778  {
7779  /*
7780  * Doing a hard exit here is a bit grotty, but it doesn't seem worth
7781  * complicating the API to make it less grotty.
7782  */
7783  pg_fatal("too many client connections for select()");
7784  }
7785  FD_SET(fd, &sa->fds);
7786  if (fd > sa->maxfd)
7787  sa->maxfd = fd;
static int fd(const char *x, int i)
Definition: preproc-init.c:105

References fd(), and pg_fatal.

Referenced by threadRun().

◆ addScript()

static void addScript ( const ParsedScript script)
static

Definition at line 6114 of file pgbench.c.

6116 {
6117  if (script->commands == NULL || script->commands[0] == NULL)
6118  pg_fatal("empty command list for script \"%s\"", script->desc);
6119 
6120  if (num_scripts >= MAX_SCRIPTS)
6121  pg_fatal("at most %d SQL scripts are allowed", MAX_SCRIPTS);
6122 
6123  CheckConditional(script);
6124 
6125  sql_script[num_scripts] = *script;
6126  num_scripts++;
static void CheckConditional(const ParsedScript *ps)
Definition: pgbench.c:5776
#define MAX_SCRIPTS
Definition: pgbench.c:356
static ParsedScript sql_script[MAX_SCRIPTS]
Definition: pgbench.c:771
static int num_scripts
Definition: pgbench.c:772
const char * desc
Definition: pgbench.c:765
Command ** commands
Definition: pgbench.c:767

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

1399 {
1400  if (ss->count == 0 || val < ss->min)
1401  ss->min = val;
1402  if (ss->count == 0 || val > ss->max)
1403  ss->max = val;
1404  ss->count++;
1405  ss->sum += val;
1406  ss->sum2 += val * val;
long val
Definition: informix.c:664
int64 count
Definition: pgbench.c:367
double sum
Definition: pgbench.c:370
double min
Definition: pgbench.c:368
double max
Definition: pgbench.c:369
double sum2
Definition: pgbench.c:371

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

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

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

7757 {
7758  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().

◆ assignVariables()

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

Definition at line 1930 of file pgbench.c.

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

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

Referenced by sendCommand().

◆ canRetryError()

static bool canRetryError ( EStatus  estatus)
static

Definition at line 3204 of file pgbench.c.

3206 {
3207  return (estatus == ESTATUS_SERIALIZATION_ERROR ||
3208  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 5776 of file pgbench.c.

5778 {
5779  /* statically check conditional structure */
5781  int i;
5782 
5783  for (i = 0; ps->commands[i] != NULL; i++)
5784  {
5785  Command *cmd = ps->commands[i];
5786 
5787  if (cmd->type == META_COMMAND)
5788  {
5789  switch (cmd->meta)
5790  {
5791  case META_IF:
5793  break;
5794  case META_ELIF:
5795  if (conditional_stack_empty(cs))
5796  ConditionError(ps->desc, i + 1, "\\elif without matching \\if");
5798  ConditionError(ps->desc, i + 1, "\\elif after \\else");
5799  break;
5800  case META_ELSE:
5801  if (conditional_stack_empty(cs))
5802  ConditionError(ps->desc, i + 1, "\\else without matching \\if");
5804  ConditionError(ps->desc, i + 1, "\\else after \\else");
5806  break;
5807  case META_ENDIF:
5808  if (!conditional_stack_pop(cs))
5809  ConditionError(ps->desc, i + 1, "\\endif without matching \\if");
5810  break;
5811  default:
5812  /* ignore anything else... */
5813  break;
5814  }
5815  }
5816  }
5817  if (!conditional_stack_empty(cs))
5818  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
int i
Definition: isn.c:73
static void ConditionError(const char *desc, int cmdn, const char *msg)
Definition: pgbench.c:5766

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

5127 {
5128  if (initialize_steps[0] == '\0')
5129  pg_fatal("no initialization steps specified");
5130 
5131  for (const char *step = initialize_steps; *step != '\0'; step++)
5132  {
5133  if (strchr(ALL_INIT_STEPS " ", *step) == NULL)
5134  {
5135  pg_log_error("unrecognized initialization step \"%c\"", *step);
5136  pg_log_error_detail("Allowed step characters are: \"" ALL_INIT_STEPS "\".");
5137  exit(1);
5138  }
5139  }
exit(1)
#define pg_log_error_detail(...)
Definition: logging.h:109
#define ALL_INIT_STEPS
Definition: pgbench.c:173

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

3036 {
3037  int i = 0;
3038  int64 w;
3039 
3040  if (num_scripts == 1)
3041  return 0;
3042 
3043  w = getrand(&thread->ts_choose_rs, 0, total_weight - 1);
3044  do
3045  {
3046  w -= sql_script[i++].weight;
3047  } while (w >= 0);
3048 
3049  return i - 1;
static int64 total_weight
Definition: pgbench.c:773
static int64 getrand(pg_prng_state *state, int64 min, int64 max)
Definition: pgbench.c:1096
int weight
Definition: pgbench.c:766
pg_prng_state ts_choose_rs
Definition: pgbench.c:665

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

7769 {
7770  FD_ZERO(&sa->fds);
7771  sa->maxfd = -1;

Referenced by threadRun().

◆ coerceToBool()

static bool coerceToBool ( PgBenchValue pval,
bool bval 
)
static

Definition at line 1998 of file pgbench.c.

2000 {
2001  if (pval->type == PGBT_BOOLEAN)
2002  {
2003  *bval = pval->u.bval;
2004  return true;
2005  }
2006  else /* NULL, INT or DOUBLE */
2007  {
2008  pg_log_error("cannot coerce %s to boolean", valueTypeName(pval));
2009  *bval = false; /* suppress uninitialized-variable warnings */
2010  return false;
2011  }
static char * valueTypeName(PgBenchValue *pval)
Definition: pgbench.c:1976
@ PGBT_BOOLEAN
Definition: pgbench.h:40
PgBenchValueType type
Definition: pgbench.h:46
bool bval
Definition: pgbench.h:51
union PgBenchValue::@32 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 2067 of file pgbench.c.

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

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

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

3027 {
3029  pg_log_info("client %d got an error in command %d (SQL) of script %d; %s",
3030  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 3015 of file pgbench.c.

3017 {
3018  pg_log_error("client %d aborted in command %d (%s) of script %d; %s",
3019  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 1590 of file pgbench.c.

1592 {
1593  return strcmp(((const Variable *) v1)->name,
1594  ((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 1195 of file pgbench.c.

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

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

5768 {
5769  pg_fatal("condition error in script \"%s\" command %d: %s",
5770  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 5471 of file pgbench.c.

5473 {
5474  Command *my_command;
5475  char *p = skip_sql_comments(buf->data);
5476 
5477  if (p == NULL)
5478  return NULL;
5479 
5480  /* Allocate and initialize Command structure */
5481  my_command = (Command *) pg_malloc(sizeof(Command));
5482  initPQExpBuffer(&my_command->lines);
5483  appendPQExpBufferStr(&my_command->lines, p);
5484  my_command->first_line = NULL; /* this is set later */
5485  my_command->type = SQL_COMMAND;
5486  my_command->meta = META_NONE;
5487  my_command->argc = 0;
5488  my_command->retries = 0;
5489  my_command->failures = 0;
5490  memset(my_command->argv, 0, sizeof(my_command->argv));
5491  my_command->varprefix = NULL; /* allocated later, if needed */
5492  my_command->expr = NULL;
5493  initSimpleStats(&my_command->stats);
5494  my_command->prepname = NULL; /* set later, if needed */
5495 
5496  return my_command;
void * pg_malloc(size_t size)
Definition: fe_memutils.c:47
static char * buf
Definition: pg_test_fsync.c:67
static char * skip_sql_comments(char *sql_command)
Definition: pgbench.c:5436
static void initSimpleStats(SimpleStats *ss)
Definition: pgbench.c:1388
void initPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:90
void appendPQExpBufferStr(PQExpBuffer str, const char *data)
Definition: pqexpbuffer.c:367
PQExpBufferData lines
Definition: pgbench.c:749
PgBenchExpr * expr
Definition: pgbench.c:757
char * argv[MAX_ARGS]
Definition: pgbench.c:754
char * first_line
Definition: pgbench.c:750
int argc
Definition: pgbench.c:753
char * prepname
Definition: pgbench.c:755

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

4692 {
4693  PQExpBufferData query;
4694 
4695  /* we must have to create some partitions */
4696  Assert(partitions > 0);
4697 
4698  fprintf(stderr, "creating %d partitions...\n", partitions);
4699 
4700  initPQExpBuffer(&query);
4701 
4702  for (int p = 1; p <= partitions; p++)
4703  {
4705  {
4706  int64 part_size = (naccounts * (int64) scale + partitions - 1) / partitions;
4707 
4708  printfPQExpBuffer(&query,
4709  "create%s table pgbench_accounts_%d\n"
4710  " partition of pgbench_accounts\n"
4711  " for values from (",
4712  unlogged_tables ? " unlogged" : "", p);
4713 
4714  /*
4715  * For RANGE, we use open-ended partitions at the beginning and
4716  * end to allow any valid value for the primary key. Although the
4717  * actual minimum and maximum values can be derived from the
4718  * scale, it is more generic and the performance is better.
4719  */
4720  if (p == 1)
4721  appendPQExpBufferStr(&query, "minvalue");
4722  else
4723  appendPQExpBuffer(&query, INT64_FORMAT, (p - 1) * part_size + 1);
4724 
4725  appendPQExpBufferStr(&query, ") to (");
4726 
4727  if (p < partitions)
4728  appendPQExpBuffer(&query, INT64_FORMAT, p * part_size + 1);
4729  else
4730  appendPQExpBufferStr(&query, "maxvalue");
4731 
4732  appendPQExpBufferChar(&query, ')');
4733  }
4734  else if (partition_method == PART_HASH)
4735  printfPQExpBuffer(&query,
4736  "create%s table pgbench_accounts_%d\n"
4737  " partition of pgbench_accounts\n"
4738  " for values with (modulus %d, remainder %d)",
4739  unlogged_tables ? " unlogged" : "", p,
4740  partitions, p - 1);
4741  else /* cannot get there */
4742  Assert(0);
4743 
4744  /*
4745  * Per ddlinfo in initCreateTables, fillfactor is needed on table
4746  * pgbench_accounts.
4747  */
4748  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4749 
4750  executeStatement(con, query.data);
4751  }
4752 
4753  termPQExpBuffer(&query);
#define INT64_FORMAT
Definition: c.h:532
int scale
Definition: pgbench.c:191
static int partitions
Definition: pgbench.c:233
int fillfactor
Definition: pgbench.c:197
static partition_method_t partition_method
Definition: pgbench.c:243
bool unlogged_tables
Definition: pgbench.c:202
#define naccounts
Definition: pgbench.c:255
static void executeStatement(PGconn *con, const char *sql)
Definition: pgbench.c:1494
#define fprintf
Definition: port.h:242
void printfPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:235
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
Definition: pqexpbuffer.c:265
void appendPQExpBufferChar(PQExpBuffer str, char ch)
Definition: pqexpbuffer.c:378
void termPQExpBuffer(PQExpBuffer str)
Definition: pqexpbuffer.c:129

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

Referenced by initCreateTables().

◆ discardUntilSync()

static int discardUntilSync ( CState st)
static

Definition at line 3451 of file pgbench.c.

3453 {
3454  /* send a sync */
3455  if (!PQpipelineSync(st->con))
3456  {
3457  pg_log_error("client %d aborted: failed to send a pipeline sync",
3458  st->id);
3459  return 0;
3460  }
3461 
3462  /* receive PGRES_PIPELINE_SYNC and null following it */
3463  for (;;)
3464  {
3465  PGresult *res = PQgetResult(st->con);
3466 
3468  {
3469  PQclear(res);
3470  res = PQgetResult(st->con);
3471  Assert(res == NULL);
3472  break;
3473  }
3474  PQclear(res);
3475  }
3476 
3477  /* exit pipeline */
3478  if (PQexitPipelineMode(st->con) != 1)
3479  {
3480  pg_log_error("client %d aborted: failed to exit pipeline mode for rolling back the failed transaction",
3481  st->id);
3482  return 0;
3483  }
3484  return 1;
int PQexitPipelineMode(PGconn *conn)
Definition: fe-exec.c:2955
int PQpipelineSync(PGconn *conn)
Definition: fe-exec.c:3141
@ PGRES_PIPELINE_SYNC
Definition: libpq-fe.h:111

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

4658 {
4659  int i;
4660 
4661  for (i = 0; i < length; i++)
4662  finishCon(&state[i]);

References finishCon(), and i.

Referenced by main(), and threadRun().

◆ doConnect()

static PGconn* doConnect ( void  )
static

Definition at line 1525 of file pgbench.c.

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

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

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

◆ doLog()

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

Definition at line 4497 of file pgbench.c.

4500 {
4501  FILE *logfile = thread->logfile;
4503 
4504  Assert(use_log);
4505 
4506  /*
4507  * Skip the log entry if sampling is enabled and this row doesn't belong
4508  * to the random sample.
4509  */
4510  if (sample_rate != 0.0 &&
4512  return;
4513 
4514  /* should we aggregate the results or not? */
4515  if (agg_interval > 0)
4516  {
4518 
4519  /*
4520  * Loop until we reach the interval of the current moment, and print
4521  * any empty intervals in between (this may happen with very low tps,
4522  * e.g. --rate=0.1).
4523  */
4524 
4525  while ((next = agg->start_time + agg_interval * INT64CONST(1000000)) <= now)
4526  {
4527  double lag_sum = 0.0;
4528  double lag_sum2 = 0.0;
4529  double lag_min = 0.0;
4530  double lag_max = 0.0;
4531  int64 skipped = 0;
4532  int64 serialization_failures = 0;
4533  int64 deadlock_failures = 0;
4534  int64 retried = 0;
4535  int64 retries = 0;
4536 
4537  /* print aggregated report to logfile */
4538  fprintf(logfile, INT64_FORMAT " " INT64_FORMAT " %.0f %.0f %.0f %.0f",
4539  agg->start_time / 1000000, /* seconds since Unix epoch */
4540  agg->cnt,
4541  agg->latency.sum,
4542  agg->latency.sum2,
4543  agg->latency.min,
4544  agg->latency.max);
4545 
4546  if (throttle_delay)
4547  {
4548  lag_sum = agg->lag.sum;
4549  lag_sum2 = agg->lag.sum2;
4550  lag_min = agg->lag.min;
4551  lag_max = agg->lag.max;
4552  }
4553  fprintf(logfile, " %.0f %.0f %.0f %.0f",
4554  lag_sum,
4555  lag_sum2,
4556  lag_min,
4557  lag_max);
4558 
4559  if (latency_limit)
4560  skipped = agg->skipped;
4561  fprintf(logfile, " " INT64_FORMAT, skipped);
4562 
4563  if (max_tries != 1)
4564  {
4565  retried = agg->retried;
4566  retries = agg->retries;
4567  }
4568  fprintf(logfile, " " INT64_FORMAT " " INT64_FORMAT, retried, retries);
4569 
4570  if (failures_detailed)
4571  {
4572  serialization_failures = agg->serialization_failures;
4573  deadlock_failures = agg->deadlock_failures;
4574  }
4576  serialization_failures,
4577  deadlock_failures);
4578 
4579  fputc('\n', logfile);
4580 
4581  /* reset data and move to next interval */
4582  initStats(agg, next);
4583  }
4584 
4585  /* accumulate the current transaction */
4586  accumStats(agg, skipped, latency, lag, st->estatus, st->tries);
4587  }
4588  else
4589  {
4590  /* no, print raw transactions */
4591  if (!skipped && st->estatus == ESTATUS_NO_ERROR)
4592  fprintf(logfile, "%d " INT64_FORMAT " %.0f %d " INT64_FORMAT " "
4593  INT64_FORMAT,
4594  st->id, st->cnt, latency, st->use_file,
4595  now / 1000000, now % 1000000);
4596  else
4597  fprintf(logfile, "%d " INT64_FORMAT " %s %d " INT64_FORMAT " "
4598  INT64_FORMAT,
4599  st->id, st->cnt, getResultString(skipped, st->estatus),
4600  st->use_file, now / 1000000, now % 1000000);
4601 
4602  if (throttle_delay)
4603  fprintf(logfile, " %.0f", lag);
4604  if (max_tries != 1)
4605  fprintf(logfile, " %u", st->tries - 1);
4606  fputc('\n', logfile);
4607  }
static int32 next
Definition: blutils.c:219
static FILE * logfile
Definition: pg_regress.c:100
static void accumStats(StatsData *stats, bool skipped, double lat, double lag, EStatus estatus, int64 tries)
Definition: pgbench.c:1445
uint32 max_tries
Definition: pgbench.c:299
bool use_log
Definition: pgbench.c:266
int agg_interval
Definition: pgbench.c:268
static const char * getResultString(bool skipped, EStatus estatus)
Definition: pgbench.c:4466
static void initStats(StatsData *sd, pg_time_usec_t start)
Definition: pgbench.c:1428
double sample_rate
Definition: pgbench.c:207
bool failures_detailed
Definition: pgbench.c:301
pg_time_usec_t epoch_shift
Definition: pgbench.c:458
pg_time_usec_t start_time
Definition: pgbench.c:387
FILE * logfile
Definition: pgbench.c:670
pg_prng_state ts_sample_rs
Definition: pgbench.c:667

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

Referenced by processXactStats(), and threadRun().

◆ doRetry()

static bool doRetry ( CState st,
pg_time_usec_t now 
)
static

Definition at line 3405 of file pgbench.c.

3407 {
3409 
3410  /* We can only retry serialization or deadlock errors. */
3411  if (!canRetryError(st->estatus))
3412  return false;
3413 
3414  /*
3415  * We must have at least one option to limit the retrying of transactions
3416  * that got an error.
3417  */
3419 
3420  /*
3421  * We cannot retry the error if we have reached the maximum number of
3422  * tries.
3423  */
3424  if (max_tries && st->tries >= max_tries)
3425  return false;
3426 
3427  /*
3428  * We cannot retry the error if we spent too much time on this
3429  * transaction.
3430  */
3431  if (latency_limit)
3432  {
3434  if (*now - st->txn_scheduled > latency_limit)
3435  return false;
3436  }
3437 
3438  /*
3439  * We cannot retry the error if the benchmark duration is over.
3440  */
3441  if (timer_exceeded)
3442  return false;
3443 
3444  /* OK */
3445  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 1767 of file pgbench.c.

1769 {
1770  /* total number of variables required now */
1771  needed += variables->nvars;
1772 
1773  if (variables->max_vars < needed)
1774  {
1775  variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
1776  variables->vars = (Variable *)
1777  pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
1778  }
void * pg_realloc(void *ptr, size_t size)
Definition: fe_memutils.c:65
#define VARIABLES_ALLOC_MARGIN
Definition: pgbench.c:319
Variable * vars
Definition: pgbench.c:343
int nvars
Definition: pgbench.c:344
int max_vars
Definition: pgbench.c:351

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

2813 {
2814  if (isLazyFunc(func))
2815  return evalLazyFunc(st, func, args, retval);
2816  else
2817  return evalStandardFunc(st, func, args, retval);
static bool isLazyFunc(PgBenchFunction func)
Definition: pgbench.c:2119
static bool evalLazyFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2126
static bool evalStandardFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2243

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

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

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

Referenced by evalFunc().

◆ evalStandardFunc()

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

Definition at line 2243 of file pgbench.c.

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

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(), generate_unaccent_rules::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 2826 of file pgbench.c.

2828 {
2829  switch (expr->etype)
2830  {
2831  case ENODE_CONSTANT:
2832  {
2833  *retval = expr->u.constant;
2834  return true;
2835  }
2836 
2837  case ENODE_VARIABLE:
2838  {
2839  Variable *var;
2840 
2841  if ((var = lookupVariable(&st->variables, expr->u.variable.varname)) == NULL)
2842  {
2843  pg_log_error("undefined variable \"%s\"", expr->u.variable.varname);
2844  return false;
2845  }
2846 
2847  if (!makeVariableValue(var))
2848  return false;
2849 
2850  *retval = var->value;
2851  return true;
2852  }
2853 
2854  case ENODE_FUNCTION:
2855  return evalFunc(st,
2856  expr->u.function.function,
2857  expr->u.function.args,
2858  retval);
2859 
2860  default:
2861  /* internal error which should never occur */
2862  pg_fatal("unexpected enode type in evaluation: %d", expr->etype);
2863  }
static Variable * lookupVariable(Variables *variables, char *name)
Definition: pgbench.c:1598
static bool evalFunc(CState *st, PgBenchFunction func, PgBenchExprLink *args, PgBenchValue *retval)
Definition: pgbench.c:2810
static bool makeVariableValue(Variable *var)
Definition: pgbench.c:1658
@ ENODE_VARIABLE
Definition: pgbench.h:60
@ ENODE_CONSTANT
Definition: pgbench.h:59
@ ENODE_FUNCTION
Definition: pgbench.h:61
Variables variables
Definition: pgbench.c:622
union PgBenchExpr::@33 u
struct PgBenchExpr::@33::@34 variable
PgBenchValue constant
Definition: pgbench.h:115
PgBenchFunction function
Definition: pgbench.h:122
PgBenchExprType etype
Definition: pgbench.h:112
PgBenchValue value
Definition: pgbench.c:335

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

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

◆ evaluateSleep()

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

Definition at line 3360 of file pgbench.c.

3362 {
3363  char *var;
3364  int usec;
3365 
3366  if (*argv[1] == ':')
3367  {
3368  if ((var = getVariable(variables, argv[1] + 1)) == NULL)
3369  {
3370  pg_log_error("%s: undefined variable \"%s\"", argv[0], argv[1] + 1);
3371  return false;
3372  }
3373 
3374  usec = atoi(var);
3375 
3376  /* Raise an error if the value of a variable is not a number */
3377  if (usec == 0 && !isdigit((unsigned char) *var))
3378  {
3379  pg_log_error("%s: invalid sleep time \"%s\" for variable \"%s\"",
3380  argv[0], var, argv[1] + 1);
3381  return false;
3382  }
3383  }
3384  else
3385  usec = atoi(argv[1]);
3386 
3387  if (argc > 2)
3388  {
3389  if (pg_strcasecmp(argv[2], "ms") == 0)
3390  usec *= 1000;
3391  else if (pg_strcasecmp(argv[2], "s") == 0)
3392  usec *= 1000000;
3393  }
3394  else
3395  usec *= 1000000;
3396 
3397  *usecs = usec;
3398  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 4251 of file pgbench.c.

4253 {
4254  Command *command = sql_script[st->use_file].commands[st->command];
4255  int argc;
4256  char **argv;
4257 
4258  Assert(command != NULL && command->type == META_COMMAND);
4259 
4260  argc = command->argc;
4261  argv = command->argv;
4262 
4264  {
4266 
4267  initPQExpBuffer(&buf);
4268 
4269  printfPQExpBuffer(&buf, "client %d executing \\%s", st->id, argv[0]);
4270  for (int i = 1; i < argc; i++)
4271  appendPQExpBuffer(&buf, " %s", argv[i]);
4272 
4273  pg_log_debug("%s", buf.data);
4274 
4275  termPQExpBuffer(&buf);
4276  }
4277 
4278  if (command->meta == META_SLEEP)
4279  {
4280  int usec;
4281 
4282  /*
4283  * A \sleep doesn't execute anything, we just get the delay from the
4284  * argument, and enter the CSTATE_SLEEP state. (The per-command
4285  * latency will be recorded in CSTATE_SLEEP state, not here, after the
4286  * delay has elapsed.)
4287  */
4288  if (!evaluateSleep(&st->variables, argc, argv, &usec))
4289  {
4290  commandFailed(st, "sleep", "execution of meta-command failed");
4291  return CSTATE_ABORTED;
4292  }
4293 
4295  st->sleep_until = (*now) + usec;
4296  return CSTATE_SLEEP;
4297  }
4298  else if (command->meta == META_SET)
4299  {
4300  PgBenchExpr *expr = command->expr;
4301  PgBenchValue result;
4302 
4303  if (!evaluateExpr(st, expr, &result))
4304  {
4305  commandFailed(st, argv[0], "evaluation of meta-command failed");
4306  return CSTATE_ABORTED;
4307  }
4308 
4309  if (!putVariableValue(&st->variables, argv[0], argv[1], &result))
4310  {
4311  commandFailed(st, "set", "assignment of meta-command failed");
4312  return CSTATE_ABORTED;
4313  }
4314  }
4315  else if (command->meta == META_IF)
4316  {
4317  /* backslash commands with an expression to evaluate */
4318  PgBenchExpr *expr = command->expr;
4319  PgBenchValue result;
4320  bool cond;
4321 
4322  if (!evaluateExpr(st, expr, &result))
4323  {
4324  commandFailed(st, argv[0], "evaluation of meta-command failed");
4325  return CSTATE_ABORTED;
4326  }
4327 
4328  cond = valueTruth(&result);
4330  }
4331  else if (command->meta == META_ELIF)
4332  {
4333  /* backslash commands with an expression to evaluate */
4334  PgBenchExpr *expr = command->expr;
4335  PgBenchValue result;
4336  bool cond;
4337 
4339  {
4340  /* elif after executed block, skip eval and wait for endif. */
4342  return CSTATE_END_COMMAND;
4343  }
4344 
4345  if (!evaluateExpr(st, expr, &result))
4346  {
4347  commandFailed(st, argv[0], "evaluation of meta-command failed");
4348  return CSTATE_ABORTED;
4349  }
4350 
4351  cond = valueTruth(&result);
4354  }
4355  else if (command->meta == META_ELSE)
4356  {
4357  switch (conditional_stack_peek(st->cstack))
4358  {
4359  case IFSTATE_TRUE:
4361  break;
4362  case IFSTATE_FALSE: /* inconsistent if active */
4363  case IFSTATE_IGNORED: /* inconsistent if active */
4364  case IFSTATE_NONE: /* else without if */
4365  case IFSTATE_ELSE_TRUE: /* else after else */
4366  case IFSTATE_ELSE_FALSE: /* else after else */
4367  default:
4368  /* dead code if conditional check is ok */
4369  Assert(false);
4370  }
4371  }
4372  else if (command->meta == META_ENDIF)
4373  {
4376  }
4377  else if (command->meta == META_SETSHELL)
4378  {
4379  if (!runShellCommand(&st->variables, argv[1], argv + 2, argc - 2))
4380  {
4381  commandFailed(st, "setshell", "execution of meta-command failed");
4382  return CSTATE_ABORTED;
4383  }
4384  }
4385  else if (command->meta == META_SHELL)
4386  {
4387  if (!runShellCommand(&st->variables, NULL, argv + 1, argc - 1))
4388  {
4389  commandFailed(st, "shell", "execution of meta-command failed");
4390  return CSTATE_ABORTED;
4391  }
4392  }
4393  else if (command->meta == META_STARTPIPELINE)
4394  {
4395  /*
4396  * In pipeline mode, we use a workflow based on libpq pipeline
4397  * functions.
4398  */
4399  if (querymode == QUERY_SIMPLE)
4400  {
4401  commandFailed(st, "startpipeline", "cannot use pipeline mode with the simple query protocol");
4402  return CSTATE_ABORTED;
4403  }
4404 
4405  /*
4406  * If we're in prepared-query mode, we need to prepare all the
4407  * commands that are inside the pipeline before we actually start the
4408  * pipeline itself. This solves the problem that running BEGIN
4409  * ISOLATION LEVEL SERIALIZABLE in a pipeline would fail due to a
4410  * snapshot having been acquired by the prepare within the pipeline.
4411  */
4412  if (querymode == QUERY_PREPARED)
4414 
4415  if (PQpipelineStatus(st->con) != PQ_PIPELINE_OFF)
4416  {
4417  commandFailed(st, "startpipeline", "already in pipeline mode");
4418  return CSTATE_ABORTED;
4419  }
4420  if (PQenterPipelineMode(st->con) == 0)
4421  {
4422  commandFailed(st, "startpipeline", "failed to enter pipeline mode");
4423  return CSTATE_ABORTED;
4424  }
4425  }
4426  else if (command->meta == META_ENDPIPELINE)
4427  {
4428  if (PQpipelineStatus(st->con) != PQ_PIPELINE_ON)
4429  {
4430  commandFailed(st, "endpipeline", "not in pipeline mode");
4431  return CSTATE_ABORTED;
4432  }
4433  if (!PQpipelineSync(st->con))
4434  {
4435  commandFailed(st, "endpipeline", "failed to send a pipeline sync");
4436  return CSTATE_ABORTED;
4437  }
4438  /* Now wait for the PGRES_PIPELINE_SYNC and exit pipeline mode there */
4439  /* collect pending results before getting out of pipeline mode */
4440  return CSTATE_WAIT_RESULT;
4441  }
4442 
4443  /*
4444  * executing the expression or shell command might have taken a
4445  * non-negligible amount of time, so reset 'now'
4446  */
4447  *now = 0;
4448 
4449  return CSTATE_END_COMMAND;
int PQenterPipelineMode(PGconn *conn)
Definition: fe-exec.c:2924
enum pg_log_level __pg_log_level
Definition: logging.c:21
@ PG_LOG_DEBUG
Definition: logging.h:26
static QueryMode querymode
Definition: pgbench.c:720
static void prepareCommandsInPipeline(CState *st)
Definition: pgbench.c:3103
static bool runShellCommand(Variables *variables, char *variable, char **argv, int argc)
Definition: pgbench.c:2909
static bool evaluateSleep(Variables *variables, int argc, char **argv, int *usecs)
Definition: pgbench.c:3360
static bool putVariableValue(Variables *variables, const char *context, char *name, const PgBenchValue *value)
Definition: pgbench.c:1846
pg_time_usec_t sleep_until
Definition: pgbench.c:626

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, now(), PG_LOG_DEBUG, pg_log_debug, pg_time_now_lazy(), PQ_PIPELINE_OFF, PQ_PIPELINE_ON, PQenterPipelineMode(), PQpipelineStatus(), PQpipelineSync(), 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 1494 of file pgbench.c.

1496 {
1497  PGresult *res;
1498 
1499  res = PQexec(con, sql);
1501  {
1502  pg_log_error("query failed: %s", PQerrorMessage(con));
1503  pg_log_error_detail("Query was: %s", sql);
1504  exit(1);
1505  }
1506  PQclear(res);
PGresult * PQexec(PGconn *conn, const char *query)
Definition: fe-exec.c:2225

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

6043 {
6044  int i,
6045  found = 0,
6046  len = strlen(name);
6047  const BuiltinScript *result = NULL;
6048 
6049  for (i = 0; i < lengthof(builtin_script); i++)
6050  {
6051  if (strncmp(builtin_script[i].name, name, len) == 0)
6052  {
6053  result = &builtin_script[i];
6054  found++;
6055  }
6056  }
6057 
6058  /* ok, unambiguous result */
6059  if (found == 1)
6060  return result;
6061 
6062  /* error cases */
6063  if (found == 0)
6064  pg_log_error("no builtin script found for name \"%s\"", name);
6065  else /* found > 1 */
6066  pg_log_error("ambiguous builtin name: %d builtin scripts found for prefix \"%s\"", found, name);
6067 
6069  exit(1);
#define lengthof(array)
Definition: c.h:772
const void size_t len
static void listAvailableScripts(void)
Definition: pgbench.c:6029
static const BuiltinScript builtin_script[]
Definition: pgbench.c:785

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

7592 {
7593  if (st->con != NULL)
7594  {
7595  PQfinish(st->con);
7596  st->con = NULL;
7597  }

References CState::con, and PQfinish().

Referenced by advanceConnectionState(), and disconnect_all().

◆ free_command()

static void free_command ( Command command)
static

Definition at line 5500 of file pgbench.c.

5502 {
5503  termPQExpBuffer(&command->lines);
5504  pg_free(command->first_line);
5505  for (int i = 0; i < command->argc; i++)
5506  pg_free(command->argv[i]);
5507  pg_free(command->varprefix);
5508 
5509  /*
5510  * It should also free expr recursively, but this is currently not needed
5511  * as only gset commands (which do not have an expression) are freed.
5512  */
5513  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 7761 of file pgbench.c.

7763 {
7764  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 1107 of file pgbench.c.

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

4457 {
4458  return (stats->serialization_failures +
4459  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 1131 of file pgbench.c.

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

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

1241 {
1242  int64 result;
1243  int i;
1244 
1245  result = FNV_OFFSET_BASIS ^ seed;
1246  for (i = 0; i < 8; ++i)
1247  {
1248  int32 octet = val & 0xff;
1249 
1250  val = val >> 8;
1251  result = result ^ octet;
1252  result = result * FNV_PRIME;
1253  }
1254 
1255  return result;
signed int int32
Definition: c.h:478
#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 1264 of file pgbench.c.

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

References MM2_MUL, MM2_MUL_TIMES_8, MM2_ROT, and val.

Referenced by evalStandardFunc().

◆ getMetaCommand()

static MetaCommand getMetaCommand ( const char *  cmd)
static

Definition at line 2869 of file pgbench.c.

2871 {
2872  MetaCommand mc;
2873 
2874  if (cmd == NULL)
2875  mc = META_NONE;
2876  else if (pg_strcasecmp(cmd, "set") == 0)
2877  mc = META_SET;
2878  else if (pg_strcasecmp(cmd, "setshell") == 0)
2879  mc = META_SETSHELL;
2880  else if (pg_strcasecmp(cmd, "shell") == 0)
2881  mc = META_SHELL;
2882  else if (pg_strcasecmp(cmd, "sleep") == 0)
2883  mc = META_SLEEP;
2884  else if (pg_strcasecmp(cmd, "if") == 0)
2885  mc = META_IF;
2886  else if (pg_strcasecmp(cmd, "elif") == 0)
2887  mc = META_ELIF;
2888  else if (pg_strcasecmp(cmd, "else") == 0)
2889  mc = META_ELSE;
2890  else if (pg_strcasecmp(cmd, "endif") == 0)
2891  mc = META_ENDIF;
2892  else if (pg_strcasecmp(cmd, "gset") == 0)
2893  mc = META_GSET;
2894  else if (pg_strcasecmp(cmd, "aset") == 0)
2895  mc = META_ASET;
2896  else if (pg_strcasecmp(cmd, "startpipeline") == 0)
2897  mc = META_STARTPIPELINE;
2898  else if (pg_strcasecmp(cmd, "endpipeline") == 0)
2899  mc = META_ENDPIPELINE;
2900  else
2901  mc = META_NONE;
2902  return mc;
MetaCommand
Definition: pgbench.c:696

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

Referenced by process_backslash_command().

◆ getPoissonRand()

static int64 getPoissonRand ( pg_prng_state state,
double  center 
)
static

Definition at line 1173 of file pgbench.c.

1175 {
1176  /*
1177  * Use inverse transform sampling to generate a value > 0, such that the
1178  * expected (i.e. average) value is the given argument.
1179  */
1180  double uniform;
1181 
1182  /* pg_prng_double value in [0, 1), uniform in (0, 1] */
1183  uniform = 1.0 - pg_prng_double(state);
1184 
1185  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 1966 of file pgbench.c.

1969 {
1970  int i;
1971 
1972  for (i = 0; i < command->argc - 1; i++)
1973  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 1096 of file pgbench.c.

1098 {
1099  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 4466 of file pgbench.c.

4468 {
4469  if (skipped)
4470  return "skipped";
4471  else if (failures_detailed)
4472  {
4473  switch (estatus)
4474  {
4476  return "serialization";
4478  return "deadlock";
4479  default:
4480  /* internal error which should never occur */
4481  pg_fatal("unexpected error status: %d", estatus);
4482  }
4483  }
4484  else
4485  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 3187 of file pgbench.c.

3189 {
3190  if (sqlState != NULL)
3191  {
3192  if (strcmp(sqlState, ERRCODE_T_R_SERIALIZATION_FAILURE) == 0)
3194  else if (strcmp(sqlState, ERRCODE_T_R_DEADLOCK_DETECTED) == 0)
3195  return ESTATUS_DEADLOCK_ERROR;
3196  }
3197 
3198  return ESTATUS_OTHER_SQL_ERROR;
#define ERRCODE_T_R_DEADLOCK_DETECTED
Definition: pgbench.c:77
#define ERRCODE_T_R_SERIALIZATION_FAILURE
Definition: pgbench.c:76

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

Referenced by readCommandResponse().

◆ GetTableInfo()

static void GetTableInfo ( PGconn con,
bool  scale_given 
)
static

Definition at line 5230 of file pgbench.c.

5232 {
5233  PGresult *res;
5234 
5235  /*
5236  * get the scaling factor that should be same as count(*) from
5237  * pgbench_branches if this is not a custom query
5238  */
5239  res = PQexec(con, "select count(*) from pgbench_branches");
5241  {
5242  char *sqlState = PQresultErrorField(res, PG_DIAG_SQLSTATE);
5243 
5244  pg_log_error("could not count number of branches: %s", PQerrorMessage(con));
5245 
5246  if (sqlState && strcmp(sqlState, ERRCODE_UNDEFINED_TABLE) == 0)
5247  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".",
5248  PQdb(con));
5249 
5250  exit(1);
5251  }
5252  scale = atoi(PQgetvalue(res, 0, 0));
5253  if (scale < 0)
5254  pg_fatal("invalid count(*) from pgbench_branches: \"%s\"",
5255  PQgetvalue(res, 0, 0));
5256  PQclear(res);
5257 
5258  /* warn if we override user-given -s switch */
5259  if (scale_given)
5260  pg_log_warning("scale option ignored, using count from pgbench_branches table (%d)",
5261  scale);
5262 
5263  /*
5264  * Get the partition information for the first "pgbench_accounts" table
5265  * found in search_path.
5266  *
5267  * The result is empty if no "pgbench_accounts" is found.
5268  *
5269  * Otherwise, it always returns one row even if the table is not
5270  * partitioned (in which case the partition strategy is NULL).
5271  *
5272  * The number of partitions can be 0 even for partitioned tables, if no
5273  * partition is attached.
5274  *
5275  * We assume no partitioning on any failure, so as to avoid failing on an
5276  * old version without "pg_partitioned_table".
5277  */
5278  res = PQexec(con,
5279  "select o.n, p.partstrat, pg_catalog.count(i.inhparent) "
5280  "from pg_catalog.pg_class as c "
5281  "join pg_catalog.pg_namespace as n on (n.oid = c.relnamespace) "
5282  "cross join lateral (select pg_catalog.array_position(pg_catalog.current_schemas(true), n.nspname)) as o(n) "
5283  "left join pg_catalog.pg_partitioned_table as p on (p.partrelid = c.oid) "
5284  "left join pg_catalog.pg_inherits as i on (c.oid = i.inhparent) "
5285  "where c.relname = 'pgbench_accounts' and o.n is not null "
5286  "group by 1, 2 "
5287  "order by 1 asc "
5288  "limit 1");
5289 
5291  {
5292  /* probably an older version, coldly assume no partitioning */
5294  partitions = 0;
5295  }
5296  else if (PQntuples(res) == 0)
5297  {
5298  /*
5299  * This case is unlikely as pgbench already found "pgbench_branches"
5300  * above to compute the scale.
5301  */
5302  pg_log_error("no pgbench_accounts table found in search_path");
5303  pg_log_error_hint("Perhaps you need to do initialization (\"pgbench -i\") in database \"%s\".", PQdb(con));
5304  exit(1);
5305  }
5306  else /* PQntupes(res) == 1 */
5307  {
5308  /* normal case, extract partition information */
5309  if (PQgetisnull(res, 0, 1))
5311  else
5312  {
5313  char *ps = PQgetvalue(res, 0, 1);
5314 
5315  /* column must be there */
5316  Assert(ps != NULL);
5317 
5318  if (strcmp(ps, "r") == 0)
5320  else if (strcmp(ps, "h") == 0)
5322  else
5323  {
5324  /* possibly a newer version with new partition method */
5325  pg_fatal("unexpected partition method: \"%s\"", ps);
5326  }
5327  }
5328 
5329  partitions = atoi(PQgetvalue(res, 0, 2));
5330  }
5331 
5332  PQclear(res);
char * PQdb(const PGconn *conn)
Definition: fe-connect.c:6811
int PQntuples(const PGresult *res)
Definition: fe-exec.c:3310
char * PQgetvalue(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3705
int PQgetisnull(const PGresult *res, int tup_num, int field_num)
Definition: fe-exec.c:3730
char * PQresultErrorField(const PGresult *res, int fieldcode)
Definition: fe-exec.c:3295
@ PGRES_TUPLES_OK
Definition: libpq-fe.h:100
#define pg_log_error_hint(...)
Definition: logging.h:112
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:78
#define pg_log_warning(...)
Definition: pgfnames.c:24
#define PG_DIAG_SQLSTATE
Definition: postgres_ext.h:56

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

Referenced by main().

◆ getTransactionStatus()

static TStatus getTransactionStatus ( PGconn con)
static

Definition at line 3491 of file pgbench.c.

3493 {
3494  PGTransactionStatusType tx_status;
3495 
3496  tx_status = PQtransactionStatus(con);
3497  switch (tx_status)
3498  {
3499  case PQTRANS_IDLE:
3500  return TSTATUS_IDLE;
3501  case PQTRANS_INTRANS:
3502  case PQTRANS_INERROR:
3503  return TSTATUS_IN_BLOCK;
3504  case PQTRANS_UNKNOWN:
3505  /* PQTRANS_UNKNOWN is expected given a broken connection */
3506  if (PQstatus(con) == CONNECTION_BAD)
3507  return TSTATUS_CONN_ERROR;
3508  /* fall through */
3509  case PQTRANS_ACTIVE:
3510  default:
3511 
3512  /*
3513  * We cannot find out whether we are in a transaction block or
3514  * not. Internal error which should never occur.
3515  */
3516  pg_log_error("unexpected transaction status %d", tx_status);
3517  return TSTATUS_OTHER_ERROR;
3518  }
3519 
3520  /* not reached */
3521  Assert(false);
3522  return TSTATUS_OTHER_ERROR;
PGTransactionStatusType PQtransactionStatus(const PGconn *conn)
Definition: fe-connect.c:6920
PGTransactionStatusType
Definition: libpq-fe.h:117
@ PQTRANS_INTRANS
Definition: libpq-fe.h:120
@ PQTRANS_IDLE
Definition: libpq-fe.h:118
@ PQTRANS_ACTIVE
Definition: libpq-fe.h:119
@ PQTRANS_UNKNOWN
Definition: libpq-fe.h:122
@ PQTRANS_INERROR
Definition: libpq-fe.h:121

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

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

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

1227 {
1228  int64 n = max - min + 1;
1229 
1230  /* abort if parameter is invalid */
1232 
1233  return min - 1 + computeIterativeZipfian(state, n, s);
static int64 computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
Definition: pgbench.c:1195

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

7608 {
7609  timer_exceeded = true;

References timer_exceeded.

Referenced by setalarm().

◆ initCreateFKeys()

static void initCreateFKeys ( PGconn con)
static

Definition at line 5099 of file pgbench.c.

5101 {
5102  static const char *const DDLKEYs[] = {
5103  "alter table pgbench_tellers add constraint pgbench_tellers_bid_fkey foreign key (bid) references pgbench_branches",
5104  "alter table pgbench_accounts add constraint pgbench_accounts_bid_fkey foreign key (bid) references pgbench_branches",
5105  "alter table pgbench_history add constraint pgbench_history_bid_fkey foreign key (bid) references pgbench_branches",
5106  "alter table pgbench_history add constraint pgbench_history_tid_fkey foreign key (tid) references pgbench_tellers",
5107  "alter table pgbench_history add constraint pgbench_history_aid_fkey foreign key (aid) references pgbench_accounts"
5108  };
5109  int i;
5110 
5111  fprintf(stderr, "creating foreign keys...\n");
5112  for (i = 0; i < lengthof(DDLKEYs); i++)
5113  {
5114  executeStatement(con, DDLKEYs[i]);
5115  }

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

Referenced by runInitSteps().

◆ initCreatePKeys()

static void initCreatePKeys ( PGconn con)
static

Definition at line 5061 of file pgbench.c.

5063 {
5064  static const char *const DDLINDEXes[] = {
5065  "alter table pgbench_branches add primary key (bid)",
5066  "alter table pgbench_tellers add primary key (tid)",
5067  "alter table pgbench_accounts add primary key (aid)"
5068  };
5069  int i;
5070  PQExpBufferData query;
5071 
5072  fprintf(stderr, "creating primary keys...\n");
5073  initPQExpBuffer(&query);
5074 
5075  for (i = 0; i < lengthof(DDLINDEXes); i++)
5076  {
5077  resetPQExpBuffer(&query);
5078  appendPQExpBufferStr(&query, DDLINDEXes[i]);
5079 
5080  if (index_tablespace != NULL)
5081  {
5082  char *escape_tablespace;
5083 
5084  escape_tablespace = PQescapeIdentifier(con, index_tablespace,
5085  strlen(index_tablespace));
5086  appendPQExpBuffer(&query, " using index tablespace %s", escape_tablespace);
5087  PQfreemem(escape_tablespace);
5088  }
5089 
5090  executeStatement(con, query.data);
5091  }
5092 
5093  termPQExpBuffer(&query);
void PQfreemem(void *ptr)
Definition: fe-exec.c:3865
char * PQescapeIdentifier(PGconn *conn, const char *str, size_t len)
Definition: fe-exec.c:4143
char * index_tablespace
Definition: pgbench.c:227
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 4759 of file pgbench.c.

4761 {
4762  /*
4763  * Note: TPC-B requires at least 100 bytes per row, and the "filler"
4764  * fields in these table declarations were intended to comply with that.
4765  * The pgbench_accounts table complies with that because the "filler"
4766  * column is set to blank-padded empty string. But for all other tables
4767  * the columns default to NULL and so don't actually take any space. We
4768  * could fix that by giving them non-null default values. However, that
4769  * would completely break comparability of pgbench results with prior
4770  * versions. Since pgbench has never pretended to be fully TPC-B compliant
4771  * anyway, we stick with the historical behavior.
4772  */
4773  struct ddlinfo
4774  {
4775  const char *table; /* table name */
4776  const char *smcols; /* column decls if accountIDs are 32 bits */
4777  const char *bigcols; /* column decls if accountIDs are 64 bits */
4778  int declare_fillfactor;
4779  };
4780  static const struct ddlinfo DDLs[] = {
4781  {
4782  "pgbench_history",
4783  "tid int,bid int,aid int,delta int,mtime timestamp,filler char(22)",
4784  "tid int,bid int,aid bigint,delta int,mtime timestamp,filler char(22)",
4785  0
4786  },
4787  {
4788  "pgbench_tellers",
4789  "tid int not null,bid int,tbalance int,filler char(84)",
4790  "tid int not null,bid int,tbalance int,filler char(84)",
4791  1
4792  },
4793  {
4794  "pgbench_accounts",
4795  "aid int not null,bid int,abalance int,filler char(84)",
4796  "aid bigint not null,bid int,abalance int,filler char(84)",
4797  1
4798  },
4799  {
4800  "pgbench_branches",
4801  "bid int not null,bbalance int,filler char(88)",
4802  "bid int not null,bbalance int,filler char(88)",
4803  1
4804  }
4805  };
4806  int i;
4807  PQExpBufferData query;
4808 
4809  fprintf(stderr, "creating tables...\n");
4810 
4811  initPQExpBuffer(&query);
4812 
4813  for (i = 0; i < lengthof(DDLs); i++)
4814  {
4815  const struct ddlinfo *ddl = &DDLs[i];
4816 
4817  /* Construct new create table statement. */
4818  printfPQExpBuffer(&query, "create%s table %s(%s)",
4819  unlogged_tables ? " unlogged" : "",
4820  ddl->table,
4821  (scale >= SCALE_32BIT_THRESHOLD) ? ddl->bigcols : ddl->smcols);
4822 
4823  /* Partition pgbench_accounts table */
4824  if (partition_method != PART_NONE && strcmp(ddl->table, "pgbench_accounts") == 0)
4825  appendPQExpBuffer(&query,
4826  " partition by %s (aid)", PARTITION_METHOD[partition_method]);
4827  else if (ddl->declare_fillfactor)
4828  {
4829  /* fillfactor is only expected on actual tables */
4830  appendPQExpBuffer(&query, " with (fillfactor=%d)", fillfactor);
4831  }
4832 
4833  if (tablespace != NULL)
4834  {
4835  char *escape_tablespace;
4836 
4837  escape_tablespace = PQescapeIdentifier(con, tablespace, strlen(tablespace));
4838  appendPQExpBuffer(&query, " tablespace %s", escape_tablespace);
4839  PQfreemem(escape_tablespace);
4840  }
4841 
4842  executeStatement(con, query.data);
4843  }
4844 
4845  termPQExpBuffer(&query);
4846 
4847  if (partition_method != PART_NONE)
4848  createPartitions(con);
static void createPartitions(PGconn *con)
Definition: pgbench.c:4690
static const char * PARTITION_METHOD[]
Definition: pgbench.c:244
#define SCALE_32BIT_THRESHOLD
Definition: pgbench.c:264
char * tablespace
Definition: pgbench.c:226

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

4670 {
4671  fprintf(stderr, "dropping old tables...\n");
4672 
4673  /*
4674  * We drop all the tables in one command, so that whether there are
4675  * foreign key dependencies or not doesn't matter.
4676  */
4677  executeStatement(con, "drop table if exists "
4678  "pgbench_accounts, "
4679  "pgbench_branches, "
4680  "pgbench_history, "
4681  "pgbench_tellers");

References executeStatement(), and fprintf.

Referenced by runInitSteps().

◆ initGenerateDataClientSide()

static void initGenerateDataClientSide ( PGconn con)
static

Definition at line 4867 of file pgbench.c.

4869 {
4870  PQExpBufferData sql;
4871  PGresult *res;
4872  int i;
4873  int64 k;
4874  char *copy_statement;
4875 
4876  /* used to track elapsed time and estimate of the remaining time */
4877  pg_time_usec_t start;
4878  int log_interval = 1;
4879 
4880  /* Stay on the same line if reporting to a terminal */
4881  char eol = isatty(fileno(stderr)) ? '\r' : '\n';
4882 
4883  fprintf(stderr, "generating data (client-side)...\n");
4884 
4885  /*
4886  * we do all of this in one transaction to enable the backend's
4887  * data-loading optimizations
4888  */
4889  executeStatement(con, "begin");
4890 
4891  /* truncate away any old data */
4892  initTruncateTables(con);
4893 
4894  initPQExpBuffer(&sql);
4895 
4896  /*
4897  * fill branches, tellers, accounts in that order in case foreign keys
4898  * already exist
4899  */
4900  for (i = 0; i < nbranches * scale; i++)
4901  {
4902  /* "filler" column defaults to NULL */
4903  printfPQExpBuffer(&sql,
4904  "insert into pgbench_branches(bid,bbalance) values(%d,0)",
4905  i + 1);
4906  executeStatement(con, sql.data);
4907  }
4908 
4909  for (i = 0; i < ntellers * scale; i++)
4910  {
4911  /* "filler" column defaults to NULL */
4912  printfPQExpBuffer(&sql,
4913  "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)",
4914  i + 1, i / ntellers + 1);
4915  executeStatement(con, sql.data);
4916  }
4917 
4918  /*
4919  * accounts is big enough to be worth using COPY and tracking runtime
4920  */
4921 
4922  /* use COPY with FREEZE on v14 and later without partitioning */
4923  if (partitions == 0 && PQserverVersion(con) >= 140000)
4924  copy_statement = "copy pgbench_accounts from stdin with (freeze on)";
4925  else
4926  copy_statement = "copy pgbench_accounts from stdin";
4927 
4928  res = PQexec(con, copy_statement);
4929 
4931  pg_fatal("unexpected copy in result: %s", PQerrorMessage(con));
4932  PQclear(res);
4933 
4934  start = pg_time_now();
4935 
4936  for (k = 0; k < (int64) naccounts * scale; k++)
4937  {
4938  int64 j = k + 1;
4939 
4940  /* "filler" column defaults to blank padded empty string */
4941  printfPQExpBuffer(&sql,
4942  INT64_FORMAT "\t" INT64_FORMAT "\t%d\t\n",
4943  j, k / naccounts + 1, 0);
4944  if (PQputline(con, sql.data))
4945  pg_fatal("PQputline failed");
4946 
4947  if (CancelRequested)
4948  break;
4949 
4950  /*
4951  * If we want to stick with the original logging, print a message each
4952  * 100k inserted rows.
4953  */
4954  if ((!use_quiet) && (j % 100000 == 0))
4955  {
4956  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4957  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4958 
4959  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4960  j, (int64) naccounts * scale,
4961  (int) (((int64) j * 100) / (naccounts * (int64) scale)),
4962  elapsed_sec, remaining_sec, eol);
4963  }
4964  /* let's not call the timing for each row, but only each 100 rows */
4965  else if (use_quiet && (j % 100 == 0))
4966  {
4967  double elapsed_sec = PG_TIME_GET_DOUBLE(pg_time_now() - start);
4968  double remaining_sec = ((double) scale * naccounts - j) * elapsed_sec / j;
4969 
4970  /* have we reached the next interval (or end)? */
4971  if ((j == scale * naccounts) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS))
4972  {
4973  fprintf(stderr, INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c",
4974  j, (int64) naccounts * scale,
4975  (int) (((int64) j * 100) / (naccounts * (int64) scale)), elapsed_sec, remaining_sec, eol);
4976 
4977  /* skip to the next interval */
4978  log_interval = (int) ceil(elapsed_sec / LOG_STEP_SECONDS);
4979  }
4980  }
4981  }
4982 
4983  if (eol != '\n')
4984  fputc('\n', stderr); /* Need to move to next line */
4985 
4986  if (PQputline(con, "\\.\n"))
4987  pg_fatal("very last PQputline failed");
4988  if (PQendcopy(con))
4989  pg_fatal("PQendcopy failed");
4990 
4991  termPQExpBuffer(&sql);
4992 
4993  executeStatement(con, "commit");
volatile sig_atomic_t CancelRequested
Definition: cancel.c:59
int PQserverVersion(const PGconn *conn)
Definition: fe-connect.c:6955
int PQendcopy(PGconn *conn)
Definition: fe-exec.c:2831
int PQputline(PGconn *conn, const char *string)
Definition: fe-exec.c:2800
int j
Definition: isn.c:74
@ PGRES_COPY_IN
Definition: libpq-fe.h:104
#define ntellers
Definition: pgbench.c:254
static void initTruncateTables(PGconn *con)
Definition: pgbench.c:4854
#define LOG_STEP_SECONDS
Definition: pgbench.c:175
#define nbranches
Definition: pgbench.c:253
bool use_quiet
Definition: pgbench.c:267

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

Referenced by runInitSteps().

◆ initGenerateDataServerSide()

static void initGenerateDataServerSide ( PGconn con)
static

Definition at line 5003 of file pgbench.c.

5005 {
5006  PQExpBufferData sql;
5007 
5008  fprintf(stderr, "generating data (server-side)...\n");
5009 
5010  /*
5011  * we do all of this in one transaction to enable the backend's
5012  * data-loading optimizations
5013  */
5014  executeStatement(con, "begin");
5015 
5016  /* truncate away any old data */
5017  initTruncateTables(con);
5018 
5019  initPQExpBuffer(&sql);
5020 
5021  printfPQExpBuffer(&sql,
5022  "insert into pgbench_branches(bid,bbalance) "
5023  "select bid, 0 "
5024  "from generate_series(1, %d) as bid", nbranches * scale);
5025  executeStatement(con, sql.data);
5026 
5027  printfPQExpBuffer(&sql,
5028  "insert into pgbench_tellers(tid,bid,tbalance) "
5029  "select tid, (tid - 1) / %d + 1, 0 "
5030  "from generate_series(1, %d) as tid", ntellers, ntellers * scale);
5031  executeStatement(con, sql.data);
5032 
5033  printfPQExpBuffer(&sql,
5034  "insert into pgbench_accounts(aid,bid,abalance,filler) "
5035  "select aid, (aid - 1) / %d + 1, 0, '' "
5036  "from generate_series(1, " INT64_FORMAT ") as aid",
5037  naccounts, (int64) naccounts * scale);
5038  executeStatement(con, sql.data);
5039 
5040  termPQExpBuffer(&sql);
5041 
5042  executeStatement(con, "commit");

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

Referenced by runInitSteps().

◆ initRandomState(