@@ -835,6 +835,8 @@ static void add_socket_to_set(socket_set *sa, int fd, int idx);
835
835
static int wait_on_socket_set (socket_set * sa , int64 usecs );
836
836
static bool socket_has_input (socket_set * sa , int fd , int idx );
837
837
838
+ /* callback used to build rows for COPY during data loading */
839
+ typedef void (* initRowMethod ) (PQExpBufferData * sql , int64 curr );
838
840
839
841
/* callback functions for our flex lexer */
840
842
static const PsqlScanCallbacks pgbench_callbacks = {
@@ -4859,17 +4861,45 @@ initTruncateTables(PGconn *con)
4859
4861
"pgbench_tellers" );
4860
4862
}
4861
4863
4862
- /*
4863
- * Fill the standard tables with some data generated and sent from the client
4864
- */
4865
4864
static void
4866
- initGenerateDataClientSide ( PGconn * con )
4865
+ initBranch ( PQExpBufferData * sql , int64 curr )
4867
4866
{
4868
- PQExpBufferData sql ;
4867
+ /* "filler" column uses NULL */
4868
+ printfPQExpBuffer (sql ,
4869
+ INT64_FORMAT "\t0\t\\N\n" ,
4870
+ curr + 1 );
4871
+ }
4872
+
4873
+ static void
4874
+ initTeller (PQExpBufferData * sql , int64 curr )
4875
+ {
4876
+ /* "filler" column uses NULL */
4877
+ printfPQExpBuffer (sql ,
4878
+ INT64_FORMAT "\t" INT64_FORMAT "\t0\t\\N\n" ,
4879
+ curr + 1 , curr / ntellers + 1 );
4880
+ }
4881
+
4882
+ static void
4883
+ initAccount (PQExpBufferData * sql , int64 curr )
4884
+ {
4885
+ /* "filler" column defaults to blank padded empty string */
4886
+ printfPQExpBuffer (sql ,
4887
+ INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n" ,
4888
+ curr + 1 , curr / naccounts + 1 );
4889
+ }
4890
+
4891
+ static void
4892
+ initPopulateTable (PGconn * con , const char * table , int64 base ,
4893
+ initRowMethod init_row )
4894
+ {
4895
+ int n ;
4896
+ int k ;
4897
+ int chars = 0 ;
4869
4898
PGresult * res ;
4870
- int i ;
4871
- int64 k ;
4872
- char * copy_statement ;
4899
+ PQExpBufferData sql ;
4900
+ char copy_statement [256 ];
4901
+ const char * copy_statement_fmt = "copy %s from stdin" ;
4902
+ int64 total = base * scale ;
4873
4903
4874
4904
/* used to track elapsed time and estimate of the remaining time */
4875
4905
pg_time_usec_t start ;
@@ -4878,50 +4908,24 @@ initGenerateDataClientSide(PGconn *con)
4878
4908
/* Stay on the same line if reporting to a terminal */
4879
4909
char eol = isatty (fileno (stderr )) ? '\r' : '\n' ;
4880
4910
4881
- fprintf (stderr , "generating data (client-side)...\n" );
4882
-
4883
- /*
4884
- * we do all of this in one transaction to enable the backend's
4885
- * data-loading optimizations
4886
- */
4887
- executeStatement (con , "begin" );
4888
-
4889
- /* truncate away any old data */
4890
- initTruncateTables (con );
4891
-
4892
4911
initPQExpBuffer (& sql );
4893
4912
4894
4913
/*
4895
- * fill branches, tellers, accounts in that order in case foreign keys
4896
- * already exist
4914
+ * Use COPY with FREEZE on v14 and later for all the tables except
4915
+ * pgbench_accounts when it is partitioned.
4897
4916
*/
4898
- for ( i = 0 ; i < nbranches * scale ; i ++ )
4917
+ if ( PQserverVersion ( con ) >= 140000 )
4899
4918
{
4900
- /* "filler" column defaults to NULL */
4901
- printfPQExpBuffer (& sql ,
4902
- "insert into pgbench_branches(bid,bbalance) values(%d,0)" ,
4903
- i + 1 );
4904
- executeStatement (con , sql .data );
4919
+ if (strcmp (table , "pgbench_accounts" ) != 0 ||
4920
+ partitions == 0 )
4921
+ copy_statement_fmt = "copy %s from stdin with (freeze on)" ;
4905
4922
}
4906
4923
4907
- for (i = 0 ; i < ntellers * scale ; i ++ )
4908
- {
4909
- /* "filler" column defaults to NULL */
4910
- printfPQExpBuffer (& sql ,
4911
- "insert into pgbench_tellers(tid,bid,tbalance) values (%d,%d,0)" ,
4912
- i + 1 , i / ntellers + 1 );
4913
- executeStatement (con , sql .data );
4914
- }
4915
-
4916
- /*
4917
- * accounts is big enough to be worth using COPY and tracking runtime
4918
- */
4919
-
4920
- /* use COPY with FREEZE on v14 and later without partitioning */
4921
- if (partitions == 0 && PQserverVersion (con ) >= 140000 )
4922
- copy_statement = "copy pgbench_accounts from stdin with (freeze on)" ;
4923
- else
4924
- copy_statement = "copy pgbench_accounts from stdin" ;
4924
+ n = pg_snprintf (copy_statement , sizeof (copy_statement ), copy_statement_fmt , table );
4925
+ if (n >= sizeof (copy_statement ))
4926
+ pg_fatal ("invalid buffer size: must be at least %d characters long" , n );
4927
+ else if (n == -1 )
4928
+ pg_fatal ("invalid format string" );
4925
4929
4926
4930
res = PQexec (con , copy_statement );
4927
4931
@@ -4931,14 +4935,11 @@ initGenerateDataClientSide(PGconn *con)
4931
4935
4932
4936
start = pg_time_now ();
4933
4937
4934
- for (k = 0 ; k < ( int64 ) naccounts * scale ; k ++ )
4938
+ for (k = 0 ; k < total ; k ++ )
4935
4939
{
4936
4940
int64 j = k + 1 ;
4937
4941
4938
- /* "filler" column defaults to blank padded empty string */
4939
- printfPQExpBuffer (& sql ,
4940
- INT64_FORMAT "\t" INT64_FORMAT "\t0\t\n" ,
4941
- j , k / naccounts + 1 );
4942
+ init_row (& sql , k );
4942
4943
if (PQputline (con , sql .data ))
4943
4944
pg_fatal ("PQputline failed" );
4944
4945
@@ -4952,41 +4953,71 @@ initGenerateDataClientSide(PGconn *con)
4952
4953
if ((!use_quiet ) && (j % 100000 == 0 ))
4953
4954
{
4954
4955
double elapsed_sec = PG_TIME_GET_DOUBLE (pg_time_now () - start );
4955
- double remaining_sec = ((double ) scale * naccounts - j ) * elapsed_sec / j ;
4956
+ double remaining_sec = ((double ) total - j ) * elapsed_sec / j ;
4956
4957
4957
- fprintf (stderr , INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c" ,
4958
- j , ( int64 ) naccounts * scale ,
4959
- (int ) ((( int64 ) j * 100 ) / ( naccounts * ( int64 ) scale ) ),
4960
- elapsed_sec , remaining_sec , eol );
4958
+ chars = fprintf (stderr , INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)%c" ,
4959
+ j , total ,
4960
+ (int ) ((j * 100 ) / total ),
4961
+ table , elapsed_sec , remaining_sec , eol );
4961
4962
}
4962
4963
/* let's not call the timing for each row, but only each 100 rows */
4963
4964
else if (use_quiet && (j % 100 == 0 ))
4964
4965
{
4965
4966
double elapsed_sec = PG_TIME_GET_DOUBLE (pg_time_now () - start );
4966
- double remaining_sec = ((double ) scale * naccounts - j ) * elapsed_sec / j ;
4967
+ double remaining_sec = ((double ) total - j ) * elapsed_sec / j ;
4967
4968
4968
4969
/* have we reached the next interval (or end)? */
4969
- if ((j == scale * naccounts ) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS ))
4970
+ if ((j == total ) || (elapsed_sec >= log_interval * LOG_STEP_SECONDS ))
4970
4971
{
4971
- fprintf (stderr , INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) done (elapsed %.2f s, remaining %.2f s)%c" ,
4972
- j , (int64 ) naccounts * scale ,
4973
- (int ) (((int64 ) j * 100 ) / (naccounts * (int64 ) scale )), elapsed_sec , remaining_sec , eol );
4972
+ chars = fprintf (stderr , INT64_FORMAT " of " INT64_FORMAT " tuples (%d%%) of %s done (elapsed %.2f s, remaining %.2f s)%c" ,
4973
+ j , total ,
4974
+ (int ) ((j * 100 ) / total ),
4975
+ table , elapsed_sec , remaining_sec , eol );
4974
4976
4975
4977
/* skip to the next interval */
4976
4978
log_interval = (int ) ceil (elapsed_sec / LOG_STEP_SECONDS );
4977
4979
}
4978
4980
}
4979
4981
}
4980
4982
4981
- if (eol != '\n' )
4982
- fputc ( '\n' , stderr ); /* Need to move to next line */
4983
+ if (chars != 0 && eol != '\n' )
4984
+ fprintf ( stderr , "%*c\r" , chars - 1 , ' ' ); /* Clear the current line */
4983
4985
4984
4986
if (PQputline (con , "\\.\n" ))
4985
4987
pg_fatal ("very last PQputline failed" );
4986
4988
if (PQendcopy (con ))
4987
4989
pg_fatal ("PQendcopy failed" );
4988
4990
4989
4991
termPQExpBuffer (& sql );
4992
+ }
4993
+
4994
+ /*
4995
+ * Fill the standard tables with some data generated and sent from the client.
4996
+ *
4997
+ * The filler column is NULL in pgbench_branches and pgbench_tellers, and is
4998
+ * a blank-padded string in pgbench_accounts.
4999
+ */
5000
+ static void
5001
+ initGenerateDataClientSide (PGconn * con )
5002
+ {
5003
+ fprintf (stderr , "generating data (client-side)...\n" );
5004
+
5005
+ /*
5006
+ * we do all of this in one transaction to enable the backend's
5007
+ * data-loading optimizations
5008
+ */
5009
+ executeStatement (con , "begin" );
5010
+
5011
+ /* truncate away any old data */
5012
+ initTruncateTables (con );
5013
+
5014
+ /*
5015
+ * fill branches, tellers, accounts in that order in case foreign keys
5016
+ * already exist
5017
+ */
5018
+ initPopulateTable (con , "pgbench_branches" , nbranches , initBranch );
5019
+ initPopulateTable (con , "pgbench_tellers" , ntellers , initTeller );
5020
+ initPopulateTable (con , "pgbench_accounts" , naccounts , initAccount );
4990
5021
4991
5022
executeStatement (con , "commit" );
4992
5023
}
0 commit comments