]> granicus.if.org Git - postgresql/blob - contrib/pgbench/pgbench.c
Standardize on __CYGWIN__ rather than __CYGWIN32__ macro. Doesn't matter
[postgresql] / contrib / pgbench / pgbench.c
1 /*
2  * $Header: /cvsroot/pgsql/contrib/pgbench/pgbench.c,v 1.6 2000/09/29 13:53:29 petere Exp $
3  *
4  * pgbench: a simple TPC-B like benchmark program for PostgreSQL
5  * written by Tatsuo Ishii
6  *
7  * Copyright (c) 2000  Tatsuo Ishii
8  *
9  * Permission to use, copy, modify, and distribute this software and
10  * its documentation for any purpose and without fee is hereby
11  * granted, provided that the above copyright notice appear in all
12  * copies and that both that copyright notice and this permission
13  * notice appear in supporting documentation, and that the name of the
14  * author not be used in advertising or publicity pertaining to
15  * distribution of the software without specific, written prior
16  * permission. The author makes no representations about the
17  * suitability of this software for any purpose.  It is provided "as
18  * is" without express or implied warranty.
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include "postgres.h"
25 #include "libpq-fe.h"
26
27 #include <errno.h>
28
29 #ifdef WIN32
30 #include "win32.h"
31 #else
32 #include <sys/time.h>
33 #include <unistd.h>
34
35 #ifdef HAVE_GETOPT_H
36 #include <getopt.h>
37 #endif
38
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
41 #endif
42
43 /* for getrlimit */
44 #include <sys/resource.h>
45
46 #endif   /* WIN32 */
47
48 /********************************************************************
49  * some configurable parameters */
50
51 #define MAXCLIENTS 1024                 /* max number of clients allowed */
52
53 int                     nclients = 1;           /* default number of simulated clients */
54 int                     nxacts = 10;            /* default number of transactions per
55                                                                  * clients */
56
57 /*
58  * scaling factor. for example, tps = 10 will make 1000000 tuples of
59  * accounts table.
60  */
61 int                     tps = 1;
62
63 /*
64  * end of configurable parameters
65  *********************************************************************/
66
67 #define nbranches       1
68 #define ntellers        10
69 #define naccounts       100000
70
71 int                     remains;                        /* number of remained clients */
72
73 typedef struct
74 {
75         PGconn     *con;                        /* connection handle to DB */
76         int                     state;                  /* state No. */
77         int                     cnt;                    /* xacts count */
78         int                     ecnt;                   /* error count */
79         int                     listen;                 /* none 0 indicates that an async query
80                                                                  * has been sent */
81         int                     aid;                    /* account id for this transaction */
82         int                     bid;                    /* branch id for this transaction */
83         int                     tid;                    /* teller id for this transaction */
84         int                     delta;
85         int                     abalance;
86 }                       CState;
87
88 static void
89 usage()
90 {
91         fprintf(stderr, "usage: pgbench [-h hostname][-p port][-c nclients][-t ntransactions][-s scaling_factor][-n][-v][-S][-d][dbname]\n");
92         fprintf(stderr, "(initialize mode): pgbench -i [-h hostname][-p port][-s scaling_factor][-d][dbname]\n");
93 }
94
95 /* random number generator */
96 static int
97 getrand(int min, int max)
98 {
99         return (min + (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)));
100 }
101
102 /* throw away response from backend */
103 static void
104 discard_response(CState * state)
105 {
106         PGresult   *res;
107
108         do
109         {
110                 res = PQgetResult(state->con);
111                 if (res)
112                         PQclear(res);
113         } while (res);
114 }
115
116 static int
117 check(CState * state, PGresult *res, int n, int good)
118 {
119         CState     *st = &state[n];
120
121         if (res && PQresultStatus(res) != good)
122         {
123                 fprintf(stderr, "Client %d aborted in state %d: %s", n, st->state, PQerrorMessage(st->con));
124                 remains--;                              /* I've aborted */
125                 PQfinish(st->con);
126                 st->con = NULL;
127                 return (-1);
128         }
129         return (0);
130 }
131
132 /* process a transaction */
133 static void
134 doOne(CState * state, int n, int debug)
135 {
136         char            sql[256];
137         PGresult   *res;
138         CState     *st = &state[n];
139
140         if (st->listen)
141         {                                                       /* are we receiver? */
142                 if (debug)
143                         fprintf(stderr, "client %d receiving\n", n);
144                 while (PQisBusy(st->con) == TRUE)
145                 {
146                         if (!PQconsumeInput(st->con))
147                         {                                       /* there's something wrong */
148                                 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
149                                 remains--;              /* I've aborted */
150                                 PQfinish(st->con);
151                                 st->con = NULL;
152                                 return;
153                         }
154                 }
155
156                 switch (st->state)
157                 {
158                         case 0:                         /* response to "begin" */
159                                 res = PQgetResult(st->con);
160                                 if (check(state, res, n, PGRES_COMMAND_OK))
161                                         return;
162                                 PQclear(res);
163                                 discard_response(st);
164                                 break;
165                         case 1:                         /* response to "update accounts..." */
166                                 res = PQgetResult(st->con);
167                                 if (check(state, res, n, PGRES_COMMAND_OK))
168                                         return;
169                                 PQclear(res);
170                                 discard_response(st);
171                                 break;
172                         case 2:                         /* response to "select abalance ..." */
173                                 res = PQgetResult(st->con);
174                                 if (check(state, res, n, PGRES_TUPLES_OK))
175                                         return;
176                                 PQclear(res);
177                                 discard_response(st);
178                                 break;
179                         case 3:                         /* response to "update tellers ..." */
180                                 res = PQgetResult(st->con);
181                                 if (check(state, res, n, PGRES_COMMAND_OK))
182                                         return;
183                                 PQclear(res);
184                                 discard_response(st);
185                                 break;
186                         case 4:                         /* response to "update branches ..." */
187                                 res = PQgetResult(st->con);
188                                 if (check(state, res, n, PGRES_COMMAND_OK))
189                                         return;
190                                 PQclear(res);
191                                 discard_response(st);
192                                 break;
193                         case 5:                         /* response to "insert into history ..." */
194                                 res = PQgetResult(st->con);
195                                 if (check(state, res, n, PGRES_COMMAND_OK))
196                                         return;
197                                 PQclear(res);
198                                 discard_response(st);
199                                 break;
200                         case 6:                         /* response to "end" */
201                                 res = PQgetResult(st->con);
202                                 if (check(state, res, n, PGRES_COMMAND_OK))
203                                         return;
204                                 PQclear(res);
205                                 discard_response(st);
206
207                                 if (++st->cnt >= nxacts)
208                                 {
209                                         remains--;      /* I've done */
210                                         PQfinish(st->con);
211                                         st->con = NULL;
212                                         return;
213                                 }
214                                 break;
215                 }
216
217                 /* increment state counter */
218                 st->state++;
219                 if (st->state > 6)
220                         st->state = 0;
221         }
222
223         switch (st->state)
224         {
225                 case 0:                 /* about to start */
226                         strcpy(sql, "begin");
227                         st->aid = getrand(1, naccounts * tps);
228                         st->bid = getrand(1, nbranches * tps);
229                         st->tid = getrand(1, ntellers * tps);
230                         st->delta = getrand(1, 1000);
231                         break;
232                 case 1:
233                         sprintf(sql, "update accounts set abalance = abalance + %d where aid = %d\n", st->delta, st->aid);
234                         break;
235                 case 2:
236                         sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
237                         break;
238                 case 3:
239                         sprintf(sql, "update tellers set tbalance = tbalance + %d where tid = %d\n",
240                                         st->delta, st->tid);
241                         break;
242                 case 4:
243                         sprintf(sql, "update branches set bbalance = bbalance + %d where bid = %d", st->delta, st->bid);
244                         break;
245                 case 5:
246                         sprintf(sql, "insert into history(tid,bid,aid,delta,time) values(%d,%d,%d,%d,'now')",
247                                         st->tid, st->bid, st->aid, st->delta);
248                         break;
249                 case 6:
250                         strcpy(sql, "end");
251                         break;
252         }
253
254         if (debug)
255                 fprintf(stderr, "client %d sending %s\n", n, sql);
256         if (PQsendQuery(st->con, sql) == 0)
257         {
258                 if (debug)
259                         fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
260                 st->ecnt++;
261         }
262         else
263         {
264                 st->listen++;                   /* flags that should be listned */
265         }
266 }
267
268 /* process a select only transaction */
269 static void
270 doSelectOnly(CState * state, int n, int debug)
271 {
272         char            sql[256];
273         PGresult   *res;
274         CState     *st = &state[n];
275
276         if (st->listen)
277         {                                                       /* are we receiver? */
278                 if (debug)
279                         fprintf(stderr, "client %d receiving\n", n);
280                 while (PQisBusy(st->con) == TRUE)
281                 {
282                         if (!PQconsumeInput(st->con))
283                         {                                       /* there's something wrong */
284                                 fprintf(stderr, "Client %d aborted in state %d. Probably the backend died while processing.\n", n, st->state);
285                                 remains--;              /* I've aborted */
286                                 PQfinish(st->con);
287                                 st->con = NULL;
288                                 return;
289                         }
290                 }
291
292                 switch (st->state)
293                 {
294                         case 0:                         /* response to "select abalance ..." */
295                                 res = PQgetResult(st->con);
296                                 if (check(state, res, n, PGRES_TUPLES_OK))
297                                         return;
298                                 PQclear(res);
299                                 discard_response(st);
300
301                                 if (++st->cnt >= nxacts)
302                                 {
303                                         remains--;      /* I've done */
304                                         PQfinish(st->con);
305                                         st->con = NULL;
306                                         return;
307                                 }
308                                 break;
309                 }
310
311                 /* increment state counter */
312                 st->state++;
313                 if (st->state > 0)
314                         st->state = 0;
315         }
316
317         switch (st->state)
318         {
319                 case 0:
320                         st->aid = getrand(1, naccounts * tps);
321                         sprintf(sql, "select abalance from accounts where aid = %d", st->aid);
322                         break;
323         }
324
325         if (debug)
326                 fprintf(stderr, "client %d sending %s\n", n, sql);
327
328         if (PQsendQuery(st->con, sql) == 0)
329         {
330                 if (debug)
331                         fprintf(stderr, "PQsendQuery(%s)failed\n", sql);
332                 st->ecnt++;
333         }
334         else
335         {
336                 st->listen++;                   /* flags that should be listned */
337         }
338 }
339
340 /* discard connections */
341 static void
342 disconnect_all(CState * state)
343 {
344         int                     i;
345
346         for (i = 0; i < nclients; i++)
347         {
348                 if (state[i].con)
349                         PQfinish(state[i].con);
350         }
351 }
352
353 /* create tables and setup data */
354 static void
355 init(char *pghost, char *pgport, char *dbName)
356 {
357         PGconn     *con;
358         PGresult   *res;
359         static char *DDLs[] = {
360                 "drop table branches",
361                 "create table branches(bid int, primary key(bid),bbalance int,filler char(88))",
362                 "drop table tellers",
363                 "create table tellers(tid int, primary key(tid),bid int,tbalance int,filler char(84))",
364                 "drop table accounts",
365                 "create table accounts(aid int,primary key(aid),bid int,abalance int,filler char(84))",
366                 "drop table history",
367         "create table history(tid int,bid int,aid int,delta int,time timestamp,filler char(22))"};
368         char            sql[256];
369
370         int                     i;
371
372         con = PQsetdb(pghost, pgport, NULL, NULL, dbName);
373         if (PQstatus(con) == CONNECTION_BAD)
374         {
375                 fprintf(stderr, "Connection to database '%s' on %s failed.\n", dbName, pghost);
376                 fprintf(stderr, "%s", PQerrorMessage(con));
377                 exit(1);
378         }
379
380         for (i = 0; i < (sizeof(DDLs) / sizeof(char *)); i++)
381         {
382                 res = PQexec(con, DDLs[i]);
383                 if (strncmp(DDLs[i], "drop", 4) && PQresultStatus(res) != PGRES_COMMAND_OK)
384                 {
385                         fprintf(stderr, "%s", PQerrorMessage(con));
386                         exit(1);
387                 }
388                 PQclear(res);
389         }
390
391         res = PQexec(con, "begin");
392         if (PQresultStatus(res) != PGRES_COMMAND_OK)
393         {
394                 fprintf(stderr, "%s", PQerrorMessage(con));
395                 exit(1);
396         }
397
398         for (i = 0; i < nbranches * tps; i++)
399         {
400                 sprintf(sql, "insert into branches(bid,bbalance) values(%d,0)", i + 1);
401                 res = PQexec(con, sql);
402                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
403                 {
404                         fprintf(stderr, "%s", PQerrorMessage(con));
405                         exit(1);
406                 }
407                 PQclear(res);
408         }
409
410         for (i = 0; i < ntellers * tps; i++)
411         {
412                 sprintf(sql, "insert into tellers(tid,bid,tbalance) values (%d,%d,0)"
413                                 ,i + 1, i / ntellers + 1);
414                 res = PQexec(con, sql);
415                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
416                 {
417                         fprintf(stderr, "%s", PQerrorMessage(con));
418                         exit(1);
419                 }
420                 PQclear(res);
421         }
422
423         res = PQexec(con, "copy accounts from stdin");
424         if (PQresultStatus(res) != PGRES_COPY_IN)
425         {
426                 fprintf(stderr, "%s", PQerrorMessage(con));
427                 exit(1);
428         }
429         PQclear(res);
430
431         fprintf(stderr, "creating tables...\n");
432         for (i = 0; i < naccounts * tps; i++)
433         {
434                 int                     j = i + 1;
435
436                 sprintf(sql, "%d\t%d\t%d\t\n", i + 1, (i + 1) / naccounts, 0);
437                 if (PQputline(con, sql))
438                 {
439                         fprintf(stderr, "PQputline failed\n");
440                         exit(1);
441                 }
442                 if (j % 10000 == 0)
443                         fprintf(stderr, "%d tuples done.\n", j);
444         }
445         if (PQputline(con, "\\.\n"))
446         {
447                 fprintf(stderr, "very last PQputline failed\n");
448                 exit(1);
449         }
450
451         if (PQendcopy(con))
452         {
453                 fprintf(stderr, "PQendcopy failed\n");
454                 exit(1);
455         }
456
457         res = PQexec(con, "end");
458         if (PQresultStatus(res) != PGRES_COMMAND_OK)
459         {
460                 fprintf(stderr, "%s", PQerrorMessage(con));
461                 exit(1);
462         }
463
464         /* vacuum */
465         fprintf(stderr, "vacuum...");
466         res = PQexec(con, "vacuum analyze");
467         if (PQresultStatus(res) != PGRES_COMMAND_OK)
468         {
469                 fprintf(stderr, "%s", PQerrorMessage(con));
470                 exit(1);
471         }
472         fprintf(stderr, "done.\n");
473
474         PQfinish(con);
475 }
476
477 /* print out results */
478 static void
479 printResults(
480                          int ttype, CState * state,
481                          struct timeval * tv1, struct timeval * tv2,
482                          struct timeval * tv3)
483 {
484         double          t1,
485                                 t2;
486         int                     i;
487         int                     normal_xacts = 0;
488
489         for (i = 0; i < nclients; i++)
490                 normal_xacts += state[i].cnt;
491
492         t1 = (tv3->tv_sec - tv1->tv_sec) * 1000000.0 + (tv3->tv_usec - tv1->tv_usec);
493         t1 = normal_xacts * 1000000.0 / t1;
494
495         t2 = (tv3->tv_sec - tv2->tv_sec) * 1000000.0 + (tv3->tv_usec - tv2->tv_usec);
496         t2 = normal_xacts * 1000000.0 / t2;
497
498         printf("transaction type: %s\n", ttype == 0 ? "TPC-B (sort of)" : "SELECT only");
499         printf("scaling factor: %d\n", tps);
500         printf("number of clients: %d\n", nclients);
501         printf("number of transactions per client: %d\n", nxacts);
502         printf("number of transactions actually processed: %d/%d\n", normal_xacts, nxacts * nclients);
503         printf("tps = %f(including connections establishing)\n", t1);
504         printf("tps = %f(excluding connections establishing)\n", t2);
505 }
506
507 int
508 main(int argc, char **argv)
509 {
510         extern char *optarg;
511         extern int      optind,
512                                 opterr,
513                                 optopt;
514         int                     c;
515         char       *pghost = "";
516         char       *pgport = "";
517         char       *dbName;
518         int                     is_init_mode = 0;               /* initialize mode? */
519         int                     is_no_vacuum = 0;               /* no vacuum at all before
520                                                                                  * testing? */
521         int                     is_full_vacuum = 0;             /* do full vacuum before testing? */
522         int                     debug = 0;              /* debug flag */
523         int                     ttype = 0;              /* transaction type. 0: TPC-B, 1: SELECT
524                                                                  * only */
525
526         static CState state[MAXCLIENTS];        /* clients status */
527
528         struct timeval tv1;                     /* start up time */
529         struct timeval tv2;                     /* after establishing all connections to
530                                                                  * the backend */
531         struct timeval tv3;                     /* end time */
532
533         int                     i;
534
535         fd_set          input_mask;
536         int                     nsocks;                 /* return from select(2) */
537         int                     maxsock;                /* max socket number to be waited */
538
539 #ifndef __CYGWIN__
540         struct rlimit rlim;
541
542 #endif
543
544         PGconn     *con;
545         PGresult   *res;
546
547         while ((c = getopt(argc, argv, "ih:nvp:dc:t:s:S")) != EOF)
548         {
549                 switch (c)
550                 {
551                         case 'i':
552                                 is_init_mode++;
553                                 break;
554                         case 'h':
555                                 pghost = optarg;
556                                 break;
557                         case 'n':
558                                 is_no_vacuum++;
559                                 break;
560                         case 'v':
561                                 is_full_vacuum++;
562                                 break;
563                         case 'p':
564                                 pgport = optarg;
565                                 break;
566                         case 'd':
567                                 debug++;
568                                 break;
569                         case 'S':
570                                 ttype = 1;
571                                 break;
572                         case 'c':
573                                 nclients = atoi(optarg);
574                                 if (nclients <= 0 || nclients > MAXCLIENTS)
575                                 {
576                                         fprintf(stderr, "wrong number of clients: %d\n", nclients);
577                                         exit(1);
578                                 }
579 #ifndef __CYGWIN__
580 #ifdef RLIMIT_NOFILE                    /* most platform uses RLIMIT_NOFILE */
581                                 if (getrlimit(RLIMIT_NOFILE, &rlim) == -1)
582                                 {
583 #else                                                   /* but BSD doesn't ... */
584                                 if (getrlimit(RLIMIT_OFILE, &rlim) == -1)
585                                 {
586 #endif   /* HAVE_RLIMIT_NOFILE */
587                                         fprintf(stderr, "getrlimit failed. reason: %s\n", strerror(errno));
588                                         exit(1);
589                                 }
590                                 if (rlim.rlim_cur <= (nclients + 2))
591                                 {
592                                         fprintf(stderr, "You need at least %d open files resource but you are only allowed to use %ld.\n", nclients + 2, (long) rlim.rlim_cur);
593                                         fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
594                                         exit(1);
595                                 }
596 #endif   /* #ifndef __CYGWIN__ */
597                                 break;
598                         case 's':
599                                 tps = atoi(optarg);
600                                 if (tps <= 0)
601                                 {
602                                         fprintf(stderr, "wrong scaling factor: %d\n", tps);
603                                         exit(1);
604                                 }
605                                 break;
606                         case 't':
607                                 nxacts = atoi(optarg);
608                                 if (nxacts <= 0)
609                                 {
610                                         fprintf(stderr, "wrong number of transactions: %d\n", nxacts);
611                                         exit(1);
612                                 }
613                                 break;
614                         default:
615                                 usage();
616                                 exit(1);
617                                 break;
618                 }
619         }
620
621         if (argc > optind)
622                 dbName = argv[optind];
623         else
624         {
625                 dbName = getenv("USER");
626                 if (dbName == NULL)
627                         dbName = "";
628         }
629
630         if (is_init_mode)
631         {
632                 init(pghost, pgport, dbName);
633                 exit(0);
634         }
635
636         remains = nclients;
637
638         if (debug)
639         {
640                 printf("pghost: %s pgport: %s nclients: %d nxacts: %d dbName: %s\n",
641                            pghost, pgport, nclients, nxacts, dbName);
642         }
643
644         /* opening connection... */
645         con = PQsetdb(pghost, pgport, NULL, NULL, dbName);
646         if (PQstatus(con) == CONNECTION_BAD)
647         {
648                 fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
649                 fprintf(stderr, "%s", PQerrorMessage(con));
650                 exit(1);
651         }
652
653         /*
654          * get the scaling factor that should be same as count(*) from
655          * branches...
656          */
657         res = PQexec(con, "select count(*) from branches");
658         if (PQresultStatus(res) != PGRES_TUPLES_OK)
659         {
660                 fprintf(stderr, "%s", PQerrorMessage(con));
661                 exit(1);
662         }
663         tps = atoi(PQgetvalue(res, 0, 0));
664         if (tps < 0)
665         {
666                 fprintf(stderr, "count(*) from branches invalid (%d)\n", tps);
667                 exit(1);
668         }
669         PQclear(res);
670
671         if (!is_no_vacuum)
672         {
673                 fprintf(stderr, "starting vacuum...");
674                 res = PQexec(con, "vacuum branches");
675                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
676                 {
677                         fprintf(stderr, "%s", PQerrorMessage(con));
678                         exit(1);
679                 }
680                 PQclear(res);
681
682                 res = PQexec(con, "vacuum tellers");
683                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
684                 {
685                         fprintf(stderr, "%s", PQerrorMessage(con));
686                         exit(1);
687                 }
688                 PQclear(res);
689
690                 res = PQexec(con, "delete from history");
691                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
692                 {
693                         fprintf(stderr, "%s", PQerrorMessage(con));
694                         exit(1);
695                 }
696                 PQclear(res);
697                 res = PQexec(con, "vacuum history");
698                 if (PQresultStatus(res) != PGRES_COMMAND_OK)
699                 {
700                         fprintf(stderr, "%s", PQerrorMessage(con));
701                         exit(1);
702                 }
703                 PQclear(res);
704
705                 fprintf(stderr, "end.\n");
706
707                 if (is_full_vacuum)
708                 {
709                         fprintf(stderr, "starting full vacuum...");
710                         res = PQexec(con, "vacuum analyze accounts");
711                         if (PQresultStatus(res) != PGRES_COMMAND_OK)
712                         {
713                                 fprintf(stderr, "%s", PQerrorMessage(con));
714                                 exit(1);
715                         }
716                         PQclear(res);
717                         fprintf(stderr, "end.\n");
718                 }
719         }
720         PQfinish(con);
721
722         /* set random seed */
723         gettimeofday(&tv1, 0);
724         srand((uint) tv1.tv_usec);
725
726         /* get start up time */
727         gettimeofday(&tv1, 0);
728
729         /* make connections to the database */
730         for (i = 0; i < nclients; i++)
731         {
732                 state[i].con = PQsetdb(pghost, pgport, NULL, NULL, dbName);
733                 if (PQstatus(state[i].con) == CONNECTION_BAD)
734                 {
735                         fprintf(stderr, "Connection to database '%s' failed.\n", dbName);
736                         fprintf(stderr, "%s", PQerrorMessage(state[i].con));
737                         exit(1);
738                 }
739         }
740
741         /* time after connections set up */
742         gettimeofday(&tv2, 0);
743
744         /* send start up quries in async manner */
745         for (i = 0; i < nclients; i++)
746         {
747                 if (ttype == 0)
748                         doOne(state, i, debug);
749                 else if (ttype == 1)
750                         doSelectOnly(state, i, debug);
751         }
752
753         for (;;)
754         {
755                 if (remains <= 0)
756                 {                                               /* all done ? */
757                         disconnect_all(state);
758                         /* get end time */
759                         gettimeofday(&tv3, 0);
760                         printResults(ttype, state, &tv1, &tv2, &tv3);
761                         exit(0);
762                 }
763
764                 FD_ZERO(&input_mask);
765
766                 maxsock = 0;
767                 for (i = 0; i < nclients; i++)
768                 {
769                         if (state[i].con)
770                         {
771                                 int                     sock = PQsocket(state[i].con);
772
773                                 if (sock < 0)
774                                 {
775                                         fprintf(stderr, "Client %d: PQsock failed\n", i);
776                                         disconnect_all(state);
777                                         exit(1);
778                                 }
779                                 FD_SET(sock, &input_mask);
780                                 if (maxsock < sock)
781                                         maxsock = sock;
782                         }
783                 }
784
785                 if ((nsocks = select(maxsock + 1, &input_mask, (fd_set *) NULL,
786                                                   (fd_set *) NULL, (struct timeval *) NULL)) < 0)
787                 {
788                         if (errno == EINTR)
789                                 continue;
790                         /* must be something wrong */
791                         disconnect_all(state);
792                         fprintf(stderr, "select failed: %s\n", strerror(errno));
793                         exit(1);
794                 }
795                 else if (nsocks == 0)
796                 {                                               /* timeout */
797                         fprintf(stderr, "select timeout\n");
798                         for (i = 0; i < nclients; i++)
799                         {
800                                 fprintf(stderr, "client %d:state %d cnt %d ecnt %d listen %d\n",
801                                                 i, state[i].state, state[i].cnt, state[i].ecnt, state[i].listen);
802                         }
803                         exit(0);
804                 }
805
806                 /* ok, backend returns reply */
807                 for (i = 0; i < nclients; i++)
808                 {
809                         if (state[i].con && FD_ISSET(PQsocket(state[i].con), &input_mask))
810                         {
811                                 if (ttype == 0)
812                                         doOne(state, i, debug);
813                                 else if (ttype == 1)
814                                         doSelectOnly(state, i, debug);
815                         }
816                 }
817         }
818 }