]> granicus.if.org Git - postgresql/blob - src/backend/tcop/postgres.c
d823dbb5a65af2e167a687a3eedf6b6bfee01d93
[postgresql] / src / backend / tcop / postgres.c
1 /*-------------------------------------------------------------------------
2  *
3  * postgres.c--
4  *        POSTGRES C Backend Interface
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.61 1998/01/13 04:04:36 scrappy Exp $
11  *
12  * NOTES
13  *        this is the "main" module of the postgres backend and
14  *        hence the main module of the "traffic cop".
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <string.h>
22 #include <signal.h>
23 #include <time.h>
24 #include <setjmp.h>
25 #include <sys/time.h>
26 #include <sys/types.h>
27 #include <fcntl.h>
28 #include <sys/param.h>                  /* for MAXHOSTNAMELEN on most */
29 #ifndef MAXHOSTNAMELEN
30 #include <netdb.h>                              /* for MAXHOSTNAMELEN on some */
31 #endif
32 #ifndef MAXHOSTNAMELEN                  /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
33 #include <sys/socket.h>
34 #endif
35 #include <errno.h>
36 #ifdef aix
37 #include <sys/select.h>
38 #endif                                                  /* aix */
39
40
41 #include "postgres.h"
42 #include "miscadmin.h"
43 #include "fmgr.h"
44
45 #include "access/xact.h"
46 #include "catalog/catname.h"
47 #include "commands/async.h"
48 #include "executor/execdebug.h"
49 #include "executor/executor.h"
50 #include "lib/dllist.h"
51 #include "libpq/libpq.h"
52 #include "libpq/pqsignal.h"
53 #include "nodes/pg_list.h"
54 #include "nodes/print.h"
55 #include "optimizer/cost.h"
56 #include "optimizer/planner.h"
57 #include "optimizer/prep.h"
58 #include "parser/parser.h"
59 #include "rewrite/rewriteHandler.h"             /* for QueryRewrite() */
60 #include "storage/bufmgr.h"
61 #include "tcop/dest.h"
62 #include "tcop/fastpath.h"
63 #include "tcop/pquery.h"
64 #include "tcop/tcopdebug.h"
65 #include "tcop/tcopprot.h"              /* where declarations for this file go */
66 #include "tcop/utility.h"
67 #include "utils/mcxt.h"
68 #include "utils/rel.h"
69
70 #if FALSE
71 #include "nodes/relation.h"
72 #endif
73
74 #if 0
75 #include "optimizer/xfunc.h"
76 #endif
77
78 #if FALSE
79 #include "nodes/plannodes.h"
80 #endif
81
82 #if FALSE
83 #include "nodes/memnodes.h"
84 #endif
85
86 static void quickdie(SIGNAL_ARGS);
87
88 /* ----------------
89  *              global variables
90  * ----------------
91  */
92 static bool DebugPrintQuery = false;
93 static bool DebugPrintPlan = false;
94 static bool DebugPrintParse = false;
95 static bool DebugPrintRewrittenParsetree = false;
96
97 /*static bool   EnableRewrite = true; , never changes why have it*/
98 CommandDest whereToSendOutput;
99
100 #ifdef LOCK_MGR_DEBUG
101 extern int      lockDebug;
102
103 #endif
104 extern int      lockingOff;
105 extern int      NBuffers;
106
107 int                     dontExecute = 0;
108 static int      ShowStats;
109 static bool IsEmptyQuery = false;
110
111 char            relname[80];            /* current relation name */
112
113 #if defined(nextstep)
114 jmp_buf         Warn_restart;
115
116 #define sigsetjmp(x,y)  setjmp(x)
117 #define siglongjmp longjmp
118 #else
119 sigjmp_buf      Warn_restart;
120
121 #endif                                                  /* defined(nextstep) */
122 int                     InError;
123
124 extern int      NBuffers;
125
126 static int      EchoQuery = 0;          /* default don't echo */
127 time_t          tim;
128 char            pg_pathname[256];
129 static int      ShowParserStats;
130 static int      ShowPlannerStats;
131 int                     ShowExecutorStats;
132 FILE       *StatFp;
133
134 typedef struct frontend
135 {
136         bool            fn_connected;
137         Port            fn_port;
138         FILE       *fn_Pfin;            /* the input fd */
139         FILE       *fn_Pfout;           /* the output fd */
140         bool            fn_done;                /* set after the frontend closes its
141                                                                  * connection */
142 } FrontEnd;
143
144 static Dllist *frontendList;
145
146 /* ----------------
147  *              people who want to use EOF should #define DONTUSENEWLINE in
148  *              tcop/tcopdebug.h
149  * ----------------
150  */
151 #ifndef TCOP_DONTUSENEWLINE
152 int                     UseNewLine = 1;         /* Use newlines query delimiters (the
153                                                                  * default) */
154
155 #else
156 int                     UseNewLine = 0;         /* Use EOF as query delimiters */
157
158 #endif                                                  /* TCOP_DONTUSENEWLINE */
159
160 /* ----------------
161  *              bushy tree plan flag: if true planner will generate bushy-tree
162  *              plans
163  * ----------------
164  */
165 int                     BushyPlanFlag = 0;      /* default to false -- consider only
166                                                                  * left-deep trees */
167
168 /*
169 ** Flags for expensive function optimization -- JMH 3/9/92
170 */
171 int                     XfuncMode = 0;
172
173 /*
174  * ----------------
175  *       Note: _exec_repeat_ defaults to 1 but may be changed
176  *                 by a DEBUG command.   If you set this to a large
177  *                 number N, run a single query, and then set it
178  *                 back to 1 and run N queries, you can get an idea
179  *                 of how much time is being spent in the parser and
180  *                 planner b/c in the first case this overhead only
181  *                 happens once.  -cim 6/9/91
182  * ----------------
183 */
184 int                     _exec_repeat_ = 1;
185
186 /* ----------------------------------------------------------------
187  *              decls for routines only used in this file
188  * ----------------------------------------------------------------
189  */
190 static char InteractiveBackend(char *inBuf);
191 static char SocketBackend(char *inBuf, bool multiplexedBackend);
192 static char ReadCommand(char *inBuf, bool multiplexedBackend);
193
194
195 /* ----------------------------------------------------------------
196  *              routines to obtain user input
197  * ----------------------------------------------------------------
198  */
199
200 /* ----------------
201  *      InteractiveBackend() is called for user interactive connections
202  *      the string entered by the user is placed in its parameter inBuf.
203  * ----------------
204  */
205
206 static char
207 InteractiveBackend(char *inBuf)
208 {
209         char       *stuff = inBuf;      /* current place in input buffer */
210         int                     c;                              /* character read from getc() */
211         bool            end = false;    /* end-of-input flag */
212         bool            backslashSeen = false;  /* have we seen a \ ? */
213
214         /* ----------------
215          *      display a prompt and obtain input from the user
216          * ----------------
217          */
218         printf("> ");
219
220         for (;;)
221         {
222                 if (UseNewLine)
223                 {
224                         /* ----------------
225                          *      if we are using \n as a delimiter, then read
226                          *      characters until the \n.
227                          * ----------------
228                          */
229                         while ((c = getc(stdin)) != EOF)
230                         {
231                                 if (c == '\n')
232                                 {
233                                         if (backslashSeen)
234                                         {
235                                                 stuff--;
236                                                 continue;
237                                         }
238                                         else
239                                         {
240                                                 /* keep the newline character */
241                                                 *stuff++ = '\n';
242                                                 *stuff++ = '\0';
243                                                 break;
244                                         }
245                                 }
246                                 else if (c == '\\')
247                                         backslashSeen = true;
248                                 else
249                                         backslashSeen = false;
250
251                                 *stuff++ = (char) c;
252                         }
253
254                         if (c == EOF)
255                                 end = true;
256                 }
257                 else
258                 {
259                         /* ----------------
260                          *      otherwise read characters until EOF.
261                          * ----------------
262                          */
263                         while ((c = getc(stdin)) != EOF)
264                                 *stuff++ = (char) c;
265
266                         if (stuff == inBuf)
267                                 end = true;
268                 }
269
270                 if (end)
271                 {
272                         if (!Quiet)
273                                 puts("EOF");
274                         IsEmptyQuery = true;
275                         exitpg(0);
276                 }
277
278                 /* ----------------
279                  *      otherwise we have a user query so process it.
280                  * ----------------
281                  */
282                 break;
283         }
284
285         /* ----------------
286          *      if the query echo flag was given, print the query..
287          * ----------------
288          */
289         if (EchoQuery)
290                 printf("query is: %s\n", inBuf);
291
292         return ('Q');
293 }
294
295 /* ----------------
296  *      SocketBackend()         Is called for frontend-backend connections
297  *
298  *      If the input is a query (case 'Q') then the string entered by
299  *      the user is placed in its parameter inBuf.
300  *
301  *      If the input is a fastpath function call (case 'F') then
302  *      the function call is processed in HandleFunctionRequest().
303  *      (now called from PostgresMain())
304  * ----------------
305  */
306
307 static char
308 SocketBackend(char *inBuf, bool multiplexedBackend)
309 {
310         char            qtype[2];
311         char            result = '\0';
312
313         /* ----------------
314          *      get input from the frontend
315          * ----------------
316          */
317         strcpy(qtype, "?");
318         if (pq_getnchar(qtype, 0, 1) == EOF)
319         {
320                 /* ------------
321                  *      when front-end applications quits/dies
322                  * ------------
323                  */
324                 if (multiplexedBackend)
325                 {
326                         return 'X';
327                 }
328                 else
329                         exitpg(0);
330         }
331
332         switch (*qtype)
333         {
334                         /* ----------------
335                          *      'Q': user entered a query
336                          * ----------------
337                          */
338                 case 'Q':
339                         pq_getstr(inBuf, MAX_PARSE_BUFFER);
340                         result = 'Q';
341                         break;
342
343                         /* ----------------
344                          *      'F':  calling user/system functions
345                          * ----------------
346                          */
347                 case 'F':
348                         pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
349                                                                                                  * line */
350                         result = 'F';
351                         break;
352
353                         /* ----------------
354                          *      'X':  frontend is exiting
355                          * ----------------
356                          */
357                 case 'X':
358                         result = 'X';
359                         break;
360
361                         /* ----------------
362                          *      otherwise we got garbage from the frontend.
363                          *
364                          *      XXX are we certain that we want to do an elog(FATAL) here?
365                          *              -cim 1/24/90
366                          * ----------------
367                          */
368                 default:
369                         elog(FATAL, "Socket command type %c unknown\n", *qtype);
370                         break;
371         }
372         return result;
373 }
374
375 /* ----------------
376  *              ReadCommand reads a command from either the frontend or
377  *              standard input, places it in inBuf, and returns a char
378  *              representing whether the string is a 'Q'uery or a 'F'astpath
379  *              call.
380  * ----------------
381  */
382 static char
383 ReadCommand(char *inBuf, bool multiplexedBackend)
384 {
385         if (IsUnderPostmaster || multiplexedBackend)
386                 return SocketBackend(inBuf, multiplexedBackend);
387         else
388                 return InteractiveBackend(inBuf);
389 }
390
391 List       *
392 pg_parse_and_plan(char *query_string,           /* string to execute */
393                 Oid *typev,                             /* argument types */
394                 int nargs,                              /* number of arguments */
395                 QueryTreeList **queryListP,             /* pointer to the parse trees */
396                 CommandDest dest)               /* where results should go */
397 {
398         QueryTreeList *querytree_list;
399         int                     i;
400         List       *plan_list = NIL;
401         Plan       *plan;
402         int                     j;
403         QueryTreeList *new_list;
404         List       *rewritten = NIL;
405         Query      *querytree;
406
407         /* ----------------
408          *      (1) parse the request string into a list of parse trees
409          * ----------------
410          */
411         if (ShowParserStats)
412                 ResetUsage();
413
414         querytree_list = parser(query_string, typev, nargs);
415
416         if (ShowParserStats)
417         {
418                 fprintf(stderr, "! Parser Stats:\n");
419                 ShowUsage();
420         }
421
422         /* new_list holds the rewritten queries */
423         new_list = (QueryTreeList *) malloc(sizeof(QueryTreeList));
424         new_list->len = querytree_list->len;
425         new_list->qtrees = (Query **) malloc(new_list->len * sizeof(Query *));
426
427         /* ----------------
428          *      (2) rewrite the queries, as necessary
429          * ----------------
430          */
431         j = 0;                                          /* counter for the new_list, new_list can
432                                                                  * be longer than old list as a result of
433                                                                  * rewrites */
434         for (i = 0; i < querytree_list->len; i++)
435         {
436                 List *union_result, *union_list, *rewritten_list;
437                 
438                 querytree = querytree_list->qtrees[i];
439
440
441                 /* don't rewrite utilites */
442                 if (querytree->commandType == CMD_UTILITY)
443                 {
444                         new_list->qtrees[j++] = querytree;
445                         continue;
446                 }
447
448                 if (DebugPrintQuery == true)
449                 {
450                         printf("\n---- \tquery is:\n%s\n", query_string);
451                         printf("\n");
452                         fflush(stdout);
453                 }
454
455                 if (DebugPrintParse == true)
456                 {
457                         printf("\n---- \tparser outputs :\n");
458                         nodeDisplay(querytree);
459                         printf("\n");
460                 }
461
462                 /* rewrite queries (retrieve, append, delete, replace) */
463                 rewritten = QueryRewrite(querytree);
464
465                 /*
466                  *      Rewrite the UNIONS.
467                  */
468                 foreach(rewritten_list, rewritten)
469                 {
470                         Query *qry = (Query *)lfirst(rewritten_list);
471                         union_result = NIL;
472                         foreach(union_list, qry->unionClause)
473                                 union_result = nconc(union_result, QueryRewrite((Query *)lfirst(union_list)));
474                         qry->unionClause = union_result;
475                 }
476
477                 if (rewritten != NULL)
478                 {
479                         int                     len,
480                                                 k;
481
482                         len = length(rewritten);
483                         if (len == 1)
484                                 new_list->qtrees[j++] = (Query *) lfirst(rewritten);
485                         else
486                         {
487                                 /* rewritten queries are longer than original query */
488                                 /* grow the new_list to accommodate */
489                                 new_list->len += len - 1;               /* - 1 because originally
490                                                                                                  * we allocated one space
491                                                                                                  * for the query */
492                                 new_list->qtrees = realloc(new_list->qtrees,
493                                                                                 new_list->len * sizeof(Query *));
494                                 for (k = 0; k < len; k++)
495                                         new_list->qtrees[j++] = (Query *) nth(k, rewritten);
496                         }
497                 }
498         }
499
500         /* we're done with the original lists, free it */
501         free(querytree_list->qtrees);
502         free(querytree_list);
503
504         querytree_list = new_list;
505
506         if (DebugPrintRewrittenParsetree == true)
507         {
508                 printf("\n---- \tafter rewriting:\n");
509
510                 for (i = 0; i < querytree_list->len; i++)
511                 {
512                         print(querytree_list->qtrees[i]);
513                         printf("\n");
514                 }
515         }
516
517         for (i = 0; i < querytree_list->len; i++)
518         {
519                 querytree = querytree_list->qtrees[i];
520
521                 /*
522                  * For each query that isn't a utility invocation, generate a
523                  * plan.
524                  */
525
526                 if (querytree->commandType != CMD_UTILITY)
527                 {
528
529                         if (IsAbortedTransactionBlockState())
530                         {
531                                 /* ----------------
532                                  *       the EndCommand() stuff is to tell the frontend
533                                  *       that the command ended. -cim 6/1/90
534                                  * ----------------
535                                  */
536                                 char       *tag = "*ABORT STATE*";
537
538                                 EndCommand(tag, dest);
539
540                                 elog(NOTICE, "(transaction aborted): %s",
541                                          "queries ignored until END");
542
543                                 *queryListP = (QueryTreeList *) NULL;
544                                 return (List *) NULL;
545                         }
546
547                         if (ShowPlannerStats)
548                                 ResetUsage();
549
550                         /* call that optimizer */
551                         plan = planner(querytree);
552
553                         if (ShowPlannerStats)
554                         {
555                                 fprintf(stderr, "! Planner Stats:\n");
556                                 ShowUsage();
557                         }
558                         plan_list = lappend(plan_list, plan);
559 #ifdef INDEXSCAN_PATCH
560                         /* ----------------
561                          *      Print plan if debugging.
562                          *      This has been moved here to get debugging output
563                          *      also for queries in functions.  DZ - 27-8-1996
564                          * ----------------
565                          */
566                         if (DebugPrintPlan == true)
567                         {
568                                 printf("\n---- \tplan is :\n");
569                                 nodeDisplay(plan);
570                                 printf("\n");
571                         }
572 #endif
573                 }
574 #ifdef FUNC_UTIL_PATCH
575
576                 /*
577                  * If the command is an utility append a null plan. This is needed
578                  * to keep the plan_list aligned with the querytree_list or the
579                  * function executor will crash.  DZ - 30-8-1996
580                  */
581                 else
582                 {
583                         plan_list = lappend(plan_list, NULL);
584                 }
585 #endif
586         }
587
588         if (queryListP)
589                 *queryListP = querytree_list;
590
591         return (plan_list);
592 }
593
594 /* ----------------------------------------------------------------
595  *              pg_exec_query()
596  *
597  *              Takes a querystring, runs the parser/utilities or
598  *              parser/planner/executor over it as necessary
599  *              Begin Transaction Should have been called before this
600  *              and CommitTransaction After this is called
601  *              This is strictly because we do not allow for nested xactions.
602  *
603  *              NON-OBVIOUS-RESTRICTIONS
604  *              this function _MUST_ allocate a new "parsetree" each time,
605  *              since it may be stored in a named portal and should not
606  *              change its value.
607  *
608  * ----------------------------------------------------------------
609  */
610
611 void
612 pg_exec_query(char *query_string, char **argv, Oid *typev, int nargs)
613 {
614         pg_exec_query_dest(query_string, argv, typev, nargs, whereToSendOutput);
615 }
616
617 void
618 pg_exec_query_dest(char *query_string,/* string to execute */
619                          char **argv,           /* arguments */
620                          Oid *typev,            /* argument types */
621                          int nargs,                     /* number of arguments */
622                          CommandDest dest)      /* where results should go */
623 {
624         List       *plan_list;
625         Plan       *plan;
626         Query      *querytree;
627         int                     i,
628                                 j;
629         QueryTreeList *querytree_list;
630
631         /* plan the queries */
632         plan_list = pg_parse_and_plan(query_string, typev, nargs, &querytree_list, dest);
633
634         /* pg_parse_and_plan could have failed */
635         if (querytree_list == NULL)
636                 return;
637
638         for (i = 0; i < querytree_list->len; i++)
639         {
640                 querytree = querytree_list->qtrees[i];
641
642 #ifdef FUNC_UTIL_PATCH
643
644                 /*
645                  * Advance on the plan_list in every case.      Now the plan_list has
646                  * the same length of the querytree_list.  DZ - 30-8-1996
647                  */
648                 plan = (Plan *) lfirst(plan_list);
649                 plan_list = lnext(plan_list);
650 #endif
651                 if (querytree->commandType == CMD_UTILITY)
652                 {
653                         /* ----------------
654                          *       process utility functions (create, destroy, etc..)
655                          *
656                          *       Note: we do not check for the transaction aborted state
657                          *       because that is done in ProcessUtility.
658                          * ----------------
659                          */
660                         if (!Quiet)
661                         {
662                                 time(&tim);
663                                 printf("\tProcessUtility() at %s\n", ctime(&tim));
664                         }
665
666                         ProcessUtility(querytree->utilityStmt, dest);
667
668                 }
669                 else
670                 {
671 #ifndef FUNC_UTIL_PATCH
672
673                         /*
674                          * Moved before the if.  DZ - 30-8-1996
675                          */
676                         plan = (Plan *) lfirst(plan_list);
677                         plan_list = lnext(plan_list);
678 #endif
679
680 #ifdef INDEXSCAN_PATCH
681
682                         /*
683                          * Print moved in pg_parse_and_plan.    DZ - 27-8-1996
684                          */
685 #else
686                         /* ----------------
687                          *      print plan if debugging
688                          * ----------------
689                          */
690                         if (DebugPrintPlan == true)
691                         {
692                                 printf("\n---- plan is :\n");
693                                 nodeDisplay(plan);
694                                 printf("\n");
695                         }
696 #endif
697
698                         /* ----------------
699                          *       execute the plan
700                          *
701                          */
702                         if (ShowExecutorStats)
703                                 ResetUsage();
704
705                         for (j = 0; j < _exec_repeat_; j++)
706                         {
707                                 if (!Quiet)
708                                 {
709                                         time(&tim);
710                                         printf("\tProcessQuery() at %s\n", ctime(&tim));
711                                 }
712                                 ProcessQuery(querytree, plan, argv, typev, nargs, dest);
713                         }
714
715                         if (ShowExecutorStats)
716                         {
717                                 fprintf(stderr, "! Executor Stats:\n");
718                                 ShowUsage();
719                         }
720                 }
721
722                 /*
723                  * In a query block, we want to increment the command counter
724                  * between queries so that the effects of early queries are
725                  * visible to subsequent ones.
726                  */
727
728                 if (querytree_list)
729                         CommandCounterIncrement();
730         }
731
732         free(querytree_list->qtrees);
733         free(querytree_list);
734 }
735
736 /* --------------------------------
737  *              signal handler routines used in PostgresMain()
738  *
739  *              handle_warn() is used to catch kill(getpid(),1) which
740  *              occurs when elog(ERROR) is called.
741  *
742  *              quickdie() occurs when signalled by the postmaster.
743  *              Some backend has bought the farm,
744  *              so we need to stop what we're doing and exit.
745  *
746  *              die() preforms an orderly cleanup via ExitPostgres()
747  * --------------------------------
748  */
749
750 void
751 handle_warn(SIGNAL_ARGS)
752 {
753         siglongjmp(Warn_restart, 1);
754 }
755
756 static void
757 quickdie(SIGNAL_ARGS)
758 {
759         elog(NOTICE, "Message from PostgreSQL backend:"
760                 "\n\tThe Postmaster has informed me that some other backend"
761                 " died abnormally and possibly corrupted shared memory."
762                 "\n\tI have rolled back the current transaction and am"
763                 " going to terminate your database system connection and exit."
764                 "\n\tPlease reconnect to the database system and repeat your query.");
765
766
767         /*
768          * DO NOT ExitPostgres(0) -- we're here because shared memory may be
769          * corrupted, so we don't want to flush any shared state to stable
770          * storage.  Just nail the windows shut and get out of town.
771          */
772
773         exit(0);
774 }
775
776 void
777 die(SIGNAL_ARGS)
778 {
779         ExitPostgres(0);
780 }
781
782 /* signal handler for floating point exception */
783 static void
784 FloatExceptionHandler(SIGNAL_ARGS)
785 {
786         elog(ERROR, "floating point exception!"
787                 " The last floating point operation either exceeded legal ranges"
788                 " or was a divide by zero");
789 }
790
791
792 static void
793 usage(char *progname)
794 {
795         fprintf(stderr,
796                         "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
797                         progname);
798         fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
799         fprintf(stderr, "    b: consider bushy plan trees during optimization\n");
800         fprintf(stderr, "    B: set number of buffers in buffer pool\n");
801         fprintf(stderr, "    C: supress version info\n");
802         fprintf(stderr, "    d: set debug level\n");
803         fprintf(stderr, "    E: echo query before execution\n");
804         fprintf(stderr, "    e  turn on European date format\n");
805         fprintf(stderr, "    F: turn off fsync\n");
806         fprintf(stderr, "    f: forbid plantype generation\n");
807         fprintf(stderr, "    i: don't execute the query, just show the plan tree\n");
808 #ifdef LOCK_MGR_DEBUG
809         fprintf(stderr, "    K: set locking debug level [0|1|2]\n");
810 #endif
811         fprintf(stderr, "    L: turn off locking\n");
812         fprintf(stderr, "    m: set up a listening backend at portno to support multiple front-ends\n");
813         fprintf(stderr, "    M: start as postmaster\n");
814         fprintf(stderr, "    N: don't use newline as query delimiter\n");
815         fprintf(stderr, "    o: send stdout and stderr to given filename \n");
816         fprintf(stderr, "    p: backend started by postmaster\n");
817         fprintf(stderr, "    P: set port file descriptor\n");
818         fprintf(stderr, "    Q: suppress informational messages\n");
819         fprintf(stderr, "    S: set amount of sort memory available\n");
820         fprintf(stderr, "    s: show stats after each query\n");
821         fprintf(stderr, "    t: trace component execution times\n");
822         fprintf(stderr, "    T: execute all possible plans for each query\n");
823         fprintf(stderr, "    x: control expensive function optimization\n");
824 }
825
826 /* ----------------------------------------------------------------
827  *              PostgresMain
828  *                postgres main loop
829  *              all backends, interactive or otherwise start here
830  * ----------------------------------------------------------------
831  */
832 int
833 PostgresMain(int argc, char *argv[])
834 {
835         int                     flagC;
836         int                     flagQ;
837         int                     flagE;
838         int                     flagEu;
839         int                     flag;
840
841         char       *DBName = NULL;
842         int                     errs = 0;
843
844         char            firstchar;
845         char            parser_input[MAX_PARSE_BUFFER];
846         char       *userName;
847
848         bool            multiplexedBackend;
849         char       *hostName;           /* the host name of the backend server */
850         int                     serverSock;
851         int                     serverPortnum = 0;
852         int                     nSelected;              /* number of descriptors ready from
853                                                                  * select(); */
854         int                     maxFd = 0;              /* max file descriptor + 1 */
855         fd_set          rmask,
856                                 basemask;
857         FrontEnd   *newFE,
858                            *currentFE = NULL;
859         int                     numFE = 0;              /* keep track of number of active
860                                                                  * frontends */
861         Port       *newPort;
862         int                     newFd;
863         Dlelem     *curr;
864         int                     status;
865
866         char       *DBDate = NULL;
867         extern int      optind;
868         extern char *optarg;
869         extern short DebugLvl;
870
871         /* ----------------
872          *      register signal handlers.
873          * ----------------
874          */
875         pqsignal(SIGINT, die);
876
877         pqsignal(SIGHUP, die);
878         pqsignal(SIGTERM, die);
879         pqsignal(SIGPIPE, die);
880         pqsignal(SIGUSR1, quickdie);
881         pqsignal(SIGUSR2, Async_NotifyHandler);
882         pqsignal(SIGFPE, FloatExceptionHandler);
883
884         /* --------------------
885          *      initialize globals
886          * -------------------
887          */
888
889         MasterPid = getpid();
890
891         /* ----------------
892          *      parse command line arguments
893          * ----------------
894          */
895
896         /*
897          * Set default values.
898          */
899         flagC = flagQ = flagE = flagEu = ShowStats = 0;
900         ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
901 #ifdef LOCK_MGR_DEBUG
902         lockDebug = 0;
903 #endif
904
905         /*
906          * get hostname is either the environment variable PGHOST or NULL
907          * NULL means Unix-socket only
908          */
909         hostName = getenv("PGHOST");
910         DataDir = getenv("PGDATA");
911         /*
912          * Try to get initial values for date styles and formats.
913          * Does not do a complete job, but should be good enough for backend.
914          * Cannot call parse_date() since palloc/pfree memory is not set up yet.
915          */
916         DBDate = getenv("PGDATESTYLE");
917         if (DBDate != NULL)
918         {
919                 if (strcasecmp(DBDate, "ISO") == 0)
920                         DateStyle = USE_ISO_DATES;
921                 else if (strcasecmp(DBDate, "SQL") == 0)
922                         DateStyle = USE_SQL_DATES;
923                 else if (strcasecmp(DBDate, "POSTGRES") == 0)
924                         DateStyle = USE_POSTGRES_DATES;
925                 else if (strcasecmp(DBDate, "GERMAN") == 0)
926                 {
927                         DateStyle = USE_GERMAN_DATES;
928                         EuroDates = TRUE;
929                 }
930
931                 if (strcasecmp(DBDate, "NONEURO") == 0)
932                         EuroDates = FALSE;
933                 else if (strcasecmp(DBDate, "EURO") == 0)
934                         EuroDates = TRUE;
935         }
936         multiplexedBackend = false;
937
938         while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:x:F"))
939                    != EOF)
940                 switch (flag)
941                 {
942
943                         case 'b':
944                                 /* ----------------
945                                  *      set BushyPlanFlag to true.
946                                  * ----------------
947                                  */
948                                 BushyPlanFlag = 1;
949                                 break;
950                         case 'B':
951                                 /* ----------------
952                                  *      specify the size of buffer pool
953                                  * ----------------
954                                  */
955                                 NBuffers = atoi(optarg);
956                                 break;
957
958                         case 'C':
959                                 /* ----------------
960                                  *      don't print version string (don't know why this is 'C' --mao)
961                                  * ----------------
962                                  */
963                                 flagC = 1;
964                                 break;
965
966                         case 'D':                       /* PGDATA directory */
967                                 DataDir = optarg;
968
969                         case 'd':                       /* debug level */
970                                 flagQ = 0;
971                                 DebugLvl = (short) atoi(optarg);
972                                 if (DebugLvl > 1)
973                                         DebugPrintQuery = true;
974                                 if (DebugLvl > 2)
975                                 {
976                                         DebugPrintParse = true;
977                                         DebugPrintPlan = true;
978                                         DebugPrintRewrittenParsetree = true;
979                                 }
980                                 break;
981
982                         case 'E':
983                                 /* ----------------
984                                  *      E - echo the query the user entered
985                                  * ----------------
986                                  */
987                                 flagE = 1;
988                                 break;
989
990                         case 'e':
991                                 /* --------------------------
992                                  * Use european date formats.
993                                  * --------------------------
994                                  */
995                                 flagEu = 1;
996                                 break;
997
998                         case 'F':
999                                 /* --------------------
1000                                  *      turn off fsync
1001                                  * --------------------
1002                                  */
1003                                 fsyncOff = 1;
1004                                 break;
1005
1006                         case 'f':
1007                                 /* -----------------
1008                                  *        f - forbid generation of certain plans
1009                                  * -----------------
1010                                  */
1011                                 switch (optarg[0])
1012                                 {
1013                                         case 's':       /* seqscan */
1014                                                 _enable_seqscan_ = false;
1015                                                 break;
1016                                         case 'i':       /* indexscan */
1017                                                 _enable_indexscan_ = false;
1018                                                 break;
1019                                         case 'n':       /* nestloop */
1020                                                 _enable_nestloop_ = false;
1021                                                 break;
1022                                         case 'm':       /* mergejoin */
1023                                                 _enable_mergesort_ = false;
1024                                                 break;
1025                                         case 'h':       /* hashjoin */
1026                                                 _enable_hashjoin_ = false;
1027                                                 break;
1028                                         default:
1029                                                 errs++;
1030                                 }
1031                                 break;
1032
1033                         case 'i':
1034                                 dontExecute = 1;
1035                                 break;
1036
1037                         case 'K':
1038 #ifdef LOCK_MGR_DEBUG
1039                                 lockDebug = atoi(optarg);
1040 #else
1041                                 fprintf(stderr, "Lock debug not compiled in\n");
1042 #endif
1043                                 break;
1044
1045                         case 'L':
1046                                 /* --------------------
1047                                  *      turn off locking
1048                                  * --------------------
1049                                  */
1050                                 lockingOff = 1;
1051                                 break;
1052
1053                         case 'm':
1054
1055                                 /*
1056                                  * start up a listening backend that can respond to
1057                                  * multiple front-ends.  (Note:  all the front-end
1058                                  * connections are still connected to a single-threaded
1059                                  * backend.  Requests are FCFS.  Everything is in one
1060                                  * transaction
1061                                  */
1062                                 multiplexedBackend = true;
1063                                 serverPortnum = atoi(optarg);
1064                                 break;
1065                         case 'M':
1066                                 exit(PostmasterMain(argc, argv));
1067                                 break;
1068                         case 'N':
1069                                 /* ----------------
1070                                  *      N - Don't use newline as a query delimiter
1071                                  * ----------------
1072                                  */
1073                                 UseNewLine = 0;
1074                                 break;
1075
1076                         case 'o':
1077                                 /* ----------------
1078                                  *      o - send output (stdout and stderr) to the given file
1079                                  * ----------------
1080                                  */
1081                                 StrNCpy(OutputFileName, optarg, MAXPGPATH);
1082                                 break;
1083
1084                         case 'p':                       /* started by postmaster */
1085                                 /* ----------------
1086                                  *      p - special flag passed if backend was forked
1087                                  *              by a postmaster.
1088                                  * ----------------
1089                                  */
1090                                 IsUnderPostmaster = true;
1091                                 break;
1092
1093                         case 'P':
1094                                 /* ----------------
1095                                  *      P - Use the passed file descriptor number as the port
1096                                  *        on which to communicate with the user.  This is ONLY
1097                                  *        useful for debugging when fired up by the postmaster.
1098                                  * ----------------
1099                                  */
1100                                 Portfd = atoi(optarg);
1101                                 break;
1102
1103                         case 'Q':
1104                                 /* ----------------
1105                                  *      Q - set Quiet mode (reduce debugging output)
1106                                  * ----------------
1107                                  */
1108                                 flagQ = 1;
1109                                 break;
1110
1111                         case 'S':
1112                                 /* ----------------
1113                                  *      S - amount of sort memory to use in 1k bytes
1114                                  * ----------------
1115                                  */
1116                                 {
1117                                         int S;
1118                                         
1119                                         S = atoi(optarg);
1120                                         if ( S >= 4*BLCKSZ/1024 )
1121                                                 SortMem = S;
1122                                 }
1123                                 break;
1124
1125                         case 's':
1126                                 /* ----------------
1127                                  *        s - report usage statistics (timings) after each query
1128                                  * ----------------
1129                                  */
1130                                 ShowStats = 1;
1131                                 StatFp = stderr;
1132                                 break;
1133
1134                         case 't':
1135                                 /* ----------------
1136                                  *      tell postgres to report usage statistics (timings) for
1137                                  *      each query
1138                                  *
1139                                  *      -tpa[rser] = print stats for parser time of each query
1140                                  *      -tpl[anner] = print stats for planner time of each query
1141                                  *      -te[xecutor] = print stats for executor time of each query
1142                                  *      caution: -s can not be used together with -t.
1143                                  * ----------------
1144                                  */
1145                                 StatFp = stderr;
1146                                 switch (optarg[0])
1147                                 {
1148                                         case 'p':
1149                                                 if (optarg[1] == 'a')
1150                                                         ShowParserStats = 1;
1151                                                 else if (optarg[1] == 'l')
1152                                                         ShowPlannerStats = 1;
1153                                                 else
1154                                                         errs++;
1155                                                 break;
1156                                         case 'e':
1157                                                 ShowExecutorStats = 1;
1158                                                 break;
1159                                         default:
1160                                                 errs++;
1161                                                 break;
1162                                 }
1163                                 break;
1164
1165                         case 'x':
1166 #if 0                                                   /* planner/xfunc.h */
1167
1168                                 /*
1169                                  * control joey hellerstein's expensive function
1170                                  * optimization
1171                                  */
1172                                 if (XfuncMode != 0)
1173                                 {
1174                                         fprintf(stderr, "only one -x flag is allowed\n");
1175                                         errs++;
1176                                         break;
1177                                 }
1178                                 if (strcmp(optarg, "off") == 0)
1179                                         XfuncMode = XFUNC_OFF;
1180                                 else if (strcmp(optarg, "nor") == 0)
1181                                         XfuncMode = XFUNC_NOR;
1182                                 else if (strcmp(optarg, "nopull") == 0)
1183                                         XfuncMode = XFUNC_NOPULL;
1184                                 else if (strcmp(optarg, "nopm") == 0)
1185                                         XfuncMode = XFUNC_NOPM;
1186                                 else if (strcmp(optarg, "pullall") == 0)
1187                                         XfuncMode = XFUNC_PULLALL;
1188                                 else if (strcmp(optarg, "wait") == 0)
1189                                         XfuncMode = XFUNC_WAIT;
1190                                 else
1191                                 {
1192                                         fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
1193                                         errs++;
1194                                 }
1195 #endif
1196                                 break;
1197
1198                         default:
1199                                 /* ----------------
1200                                  *      default: bad command line option
1201                                  * ----------------
1202                                  */
1203                                 errs++;
1204                 }
1205
1206         /* ----------------
1207          *      get user name and pathname and check command line validity
1208          * ----------------
1209          */
1210         SetPgUserName();
1211         userName = GetPgUserName();
1212
1213         if (FindBackend(pg_pathname, argv[0]) < 0)
1214                 elog(FATAL, "%s: could not locate executable, bailing out...",
1215                          argv[0]);
1216
1217         if (errs || argc - optind > 1)
1218         {
1219                 usage(argv[0]);
1220                 exitpg(1);
1221         }
1222         else if (argc - optind == 1)
1223         {
1224                 DBName = argv[optind];
1225         }
1226         else if ((DBName = userName) == NULL)
1227         {
1228                 fprintf(stderr, "%s: USER undefined and no database specified\n",
1229                                 argv[0]);
1230                 exitpg(1);
1231         }
1232
1233         if (ShowStats &&
1234                 (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
1235         {
1236                 fprintf(stderr, "-s can not be used together with -t.\n");
1237                 exitpg(1);
1238         }
1239
1240         if (!DataDir)
1241         {
1242                 fprintf(stderr, "%s does not know where to find the database system "
1243                                 "data.  You must specify the directory that contains the "
1244                                 "database system either by specifying the -D invocation "
1245                          "option or by setting the PGDATA environment variable.\n\n",
1246                                 argv[0]);
1247                 exitpg(1);
1248         }
1249
1250         Noversion = flagC;
1251         Quiet = flagQ;
1252         EchoQuery = flagE;
1253         EuroDates = flagEu;
1254
1255         /* ----------------
1256          *      print flags
1257          * ----------------
1258          */
1259         if (!Quiet)
1260         {
1261                 puts("\t---debug info---");
1262                 printf("\tQuiet =        %c\n", Quiet ? 't' : 'f');
1263                 printf("\tNoversion =    %c\n", Noversion ? 't' : 'f');
1264                 printf("\ttimings   =    %c\n", ShowStats ? 't' : 'f');
1265                 printf("\tdates     =    %s\n", EuroDates ? "European" : "Normal");
1266                 printf("\tbufsize   =    %d\n", NBuffers);
1267                 printf("\tsortmem   =    %d\n", SortMem);
1268
1269                 printf("\tquery echo =   %c\n", EchoQuery ? 't' : 'f');
1270                 printf("\tmultiplexed backend? =  %c\n", multiplexedBackend ? 't' : 'f');
1271                 printf("\tDatabaseName = [%s]\n", DBName);
1272                 puts("\t----------------\n");
1273         }
1274
1275         /* ----------------
1276          *      initialize portal file descriptors
1277          * ----------------
1278          */
1279         if (IsUnderPostmaster == true)
1280         {
1281                 if (Portfd < 0)
1282                 {
1283                         fprintf(stderr,
1284                                         "Postmaster flag set: no port number specified, use /dev/null\n");
1285                         Portfd = open(NULL_DEV, O_RDWR, 0666);
1286                 }
1287                 pq_init(Portfd);
1288         }
1289
1290         if (multiplexedBackend)
1291         {
1292                 if (serverPortnum == 0 ||
1293                     StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
1294                 {
1295                         fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
1296                         exit(1);
1297                 }
1298 /*
1299 {
1300         char buf[100];
1301         sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
1302         puts(buf);
1303 }
1304 */
1305                 FD_ZERO(&rmask);
1306                 FD_ZERO(&basemask);
1307                 FD_SET(serverSock, &basemask);
1308
1309                 frontendList = DLNewList();
1310                 /* add the original FrontEnd to the list */
1311                 if (IsUnderPostmaster == true)
1312                 {
1313                         FrontEnd   *fe = malloc(sizeof(FrontEnd));
1314
1315                         FD_SET(Portfd, &basemask);
1316                         maxFd = Max(serverSock, Portfd) + 1;
1317
1318                         fe->fn_connected = true;
1319                         fe->fn_Pfin = Pfin;
1320                         fe->fn_Pfout = Pfout;
1321                         fe->fn_done = false;
1322                         (fe->fn_port).sock = Portfd;
1323                         DLAddHead(frontendList, DLNewElem(fe));
1324                         numFE++;
1325                 }
1326                 else
1327                 {
1328                         numFE = 1;
1329                         maxFd = serverSock + 1;
1330                 }
1331         }
1332
1333         if (IsUnderPostmaster || multiplexedBackend)
1334                 whereToSendOutput = Remote;
1335         else
1336                 whereToSendOutput = Debug;
1337
1338         SetProcessingMode(InitProcessing);
1339
1340         /* initialize */
1341         if (!Quiet)
1342         {
1343                 puts("\tInitPostgres()..");
1344         }
1345
1346         InitPostgres(DBName);
1347
1348         /* ----------------
1349          *      if an exception is encountered, processing resumes here
1350          *      so we abort the current transaction and start a new one.
1351          *      This must be done after we initialize the slave backends
1352          *      so that the slaves signal the master to abort the transaction
1353          *      rather than calling AbortCurrentTransaction() themselves.
1354          *
1355          *      Note:  elog(ERROR) causes a kill(getpid(),1) to occur sending
1356          *                 us back here.
1357          * ----------------
1358          */
1359
1360         pqsignal(SIGHUP, handle_warn);
1361
1362         if (sigsetjmp(Warn_restart, 1) != 0)
1363         {
1364                 InError = 1;
1365
1366                 time(&tim);
1367
1368                 if (!Quiet)
1369                         printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
1370
1371                 MemSet(parser_input, 0, MAX_PARSE_BUFFER);
1372
1373                 AbortCurrentTransaction();
1374         }
1375         InError = 0;
1376
1377         /* ----------------
1378          *      POSTGRES main processing loop begins here
1379          * ----------------
1380          */
1381         if (IsUnderPostmaster == false)
1382         {
1383                 puts("\nPOSTGRES backend interactive interface");
1384                 puts("$Revision: 1.61 $ $Date: 1998/01/13 04:04:36 $");
1385         }
1386
1387         /* ----------------
1388          * if stable main memory is assumed (-S(old) flag is set), it is necessary
1389          * to flush all dirty shared buffers before exit
1390          * plai 8/7/90
1391          * ----------------
1392          */
1393         if (!TransactionFlushEnabled())
1394                 on_exitpg(FlushBufferPool, (caddr_t) 0);
1395
1396         for (;;)
1397         {
1398
1399                 if (multiplexedBackend)
1400                 {
1401                         if (numFE == 0)
1402                                 break;
1403
1404                         memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
1405                         nSelected = select(maxFd, &rmask, 0, 0, 0);
1406
1407                         if (nSelected < 0)
1408                         {
1409
1410                                 if (errno == EINTR)
1411                                         continue;
1412                                 fprintf(stderr, "postgres: multiplexed backend select failed\n");
1413                                 exitpg(1);
1414                         }
1415                         if (FD_ISSET(serverSock, &rmask))
1416                         {
1417                                 /* new connection pending on our well-known port's socket */
1418                                 newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
1419                                 MemSet(newFE, 0, sizeof(FrontEnd));
1420                                 newFE->fn_connected = false;
1421                                 newFE->fn_done = false;
1422                                 newPort = &(newFE->fn_port);
1423                                 if (StreamConnection(serverSock, newPort) != STATUS_OK)
1424                                 {
1425                                         StreamClose(newPort->sock);
1426                                         newFd = -1;
1427                                 }
1428                                 else
1429                                 {
1430                                         DLAddHead(frontendList, DLNewElem(newFE));
1431                                         numFE++;
1432                                         newFd = newPort->sock;
1433                                         if (newFd >= maxFd)
1434                                                 maxFd = newFd + 1;
1435                                         FD_SET(newFd, &rmask);
1436                                         FD_SET(newFd, &basemask);
1437                                         --nSelected;
1438                                         FD_CLR(serverSock, &rmask);
1439                                 }
1440                                 continue;
1441                         }                                       /* if FD_ISSET(serverSock) */
1442
1443                         /*
1444                          * if we get here, it means that the serverSocket was not the
1445                          * one selected.  Instead, one of the front ends was selected.
1446                          * find which one
1447                          */
1448                         curr = DLGetHead(frontendList);
1449                         while (curr)
1450                         {
1451                                 FrontEnd   *fe = (FrontEnd *) DLE_VAL(curr);
1452                                 Port       *port = &(fe->fn_port);
1453
1454                                 /* this is lifted from postmaster.c */
1455                                 if (FD_ISSET(port->sock, &rmask))
1456                                 {
1457                                         if (fe->fn_connected == false)
1458                                         {
1459                                                 /* we have a message from a new frontEnd */
1460                                                 status = PacketReceive(port, &port->buf, NON_BLOCKING);
1461                                                 if (status == STATUS_OK)
1462                                                 {
1463                                                         fe->fn_connected = true;
1464                                                         pq_init(port->sock);
1465                                                         fe->fn_Pfin = Pfin;
1466                                                         fe->fn_Pfout = Pfout;
1467                                                 }
1468                                                 else
1469                                                         fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
1470                                         }
1471                                         else
1472 /* we have a query from an existing,  active FrontEnd */
1473                                         {
1474                                                 Pfin = fe->fn_Pfin;
1475                                                 Pfout = fe->fn_Pfout;
1476                                                 currentFE = fe;
1477                                         }
1478                                         if (fe->fn_done)
1479                                         {
1480                                                 Dlelem     *c = curr;
1481
1482                                                 curr = DLGetSucc(curr);
1483                                                 DLRemove(c);
1484                                         }
1485                                         break;
1486                                 }
1487                                 else
1488                                         curr = DLGetSucc(curr);
1489                         }
1490                 }
1491                 /* ----------------
1492                  *       (1) read a command.
1493                  * ----------------
1494                  */
1495                 MemSet(parser_input, 0, MAX_PARSE_BUFFER);
1496
1497                 firstchar = ReadCommand(parser_input, multiplexedBackend);
1498                 /* process the command */
1499                 switch (firstchar)
1500                 {
1501                                 /* ----------------
1502                                  *      'F' indicates a fastpath call.
1503                                  *              XXX HandleFunctionRequest
1504                                  * ----------------
1505                                  */
1506                         case 'F':
1507                                 IsEmptyQuery = false;
1508
1509                                 /* start an xact for this function invocation */
1510                                 if (!Quiet)
1511                                 {
1512                                         time(&tim);
1513                                         printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1514                                 }
1515
1516                                 StartTransactionCommand();
1517                                 HandleFunctionRequest();
1518                                 break;
1519
1520                                 /* ----------------
1521                                  *      'Q' indicates a user query
1522                                  * ----------------
1523                                  */
1524                         case 'Q':
1525                                 fflush(stdout);
1526
1527                                 if (strspn(parser_input, " \t\n") == strlen(parser_input))
1528                                 {
1529                                         /* ----------------
1530                                          *      if there is nothing in the input buffer, don't bother
1531                                          *      trying to parse and execute anything..
1532                                          * ----------------
1533                                          */
1534                                         IsEmptyQuery = true;
1535                                 }
1536                                 else
1537                                 {
1538                                         /* ----------------
1539                                          *      otherwise, process the input string.
1540                                          * ----------------
1541                                          */
1542                                         IsEmptyQuery = false;
1543                                         if (ShowStats)
1544                                                 ResetUsage();
1545
1546                                         /* start an xact for this query */
1547                                         if (!Quiet)
1548                                         {
1549                                                 time(&tim);
1550                                                 printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1551                                         }
1552                                         StartTransactionCommand();
1553
1554                                         pg_exec_query(parser_input, (char **) NULL, (Oid *) NULL, 0);
1555
1556                                         if (ShowStats)
1557                                                 ShowUsage();
1558                                 }
1559                                 break;
1560
1561                                 /* ----------------
1562                                  *      'X' means that the frontend is closing down the socket
1563                                  * ----------------
1564                                  */
1565                         case 'X':
1566                                 IsEmptyQuery = true;
1567                                 if (multiplexedBackend)
1568                                 {
1569                                         FD_CLR(currentFE->fn_port.sock, &basemask);
1570                                         currentFE->fn_done = true;
1571                                         numFE--;
1572                                 }
1573                                 pq_close();
1574                                 break;
1575
1576                         default:
1577                                 elog(ERROR, "unknown frontend message was recieved");
1578                 }
1579
1580                 /* ----------------
1581                  *       (3) commit the current transaction
1582                  *
1583                  *       Note: if we had an empty input buffer, then we didn't
1584                  *       call pg_exec_query, so we don't bother to commit this transaction.
1585                  * ----------------
1586                  */
1587                 if (!IsEmptyQuery)
1588                 {
1589                         if (!Quiet)
1590                         {
1591                                 time(&tim);
1592                                 printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
1593                         }
1594                         CommitTransactionCommand();
1595
1596                 }
1597                 else
1598                 {
1599                         if (IsUnderPostmaster || multiplexedBackend)
1600                                 NullCommand(Remote);
1601                 }
1602
1603         }                                                       /* infinite for-loop */
1604         exitpg(0);
1605         return 1;
1606 }
1607
1608 #ifndef HAVE_GETRUSAGE
1609 #include "rusagestub.h"
1610 #else                                                   /* HAVE_GETRUSAGE */
1611 #include <sys/resource.h>
1612 #endif                                                  /* HAVE_GETRUSAGE */
1613
1614 struct rusage Save_r;
1615 struct timeval Save_t;
1616
1617 void
1618 ResetUsage(void)
1619 {
1620         struct timezone tz;
1621
1622         getrusage(RUSAGE_SELF, &Save_r);
1623         gettimeofday(&Save_t, &tz);
1624         ResetBufferUsage();
1625 /*        ResetTupleCount(); */
1626 }
1627
1628 void
1629 ShowUsage(void)
1630 {
1631         struct timeval user,
1632                                 sys;
1633         struct timeval elapse_t;
1634         struct timezone tz;
1635         struct rusage r;
1636
1637         getrusage(RUSAGE_SELF, &r);
1638         gettimeofday(&elapse_t, &tz);
1639         memmove((char *) &user, (char *) &r.ru_utime, sizeof(user));
1640         memmove((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
1641         if (elapse_t.tv_usec < Save_t.tv_usec)
1642         {
1643                 elapse_t.tv_sec--;
1644                 elapse_t.tv_usec += 1000000;
1645         }
1646         if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec)
1647         {
1648                 r.ru_utime.tv_sec--;
1649                 r.ru_utime.tv_usec += 1000000;
1650         }
1651         if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec)
1652         {
1653                 r.ru_stime.tv_sec--;
1654                 r.ru_stime.tv_usec += 1000000;
1655         }
1656
1657         /*
1658          * the only stats we don't show here are for memory usage -- i can't
1659          * figure out how to interpret the relevant fields in the rusage
1660          * struct, and they change names across o/s platforms, anyway. if you
1661          * can figure out what the entries mean, you can somehow extract
1662          * resident set size, shared text size, and unshared data and stack
1663          * sizes.
1664          */
1665
1666         fprintf(StatFp, "! system usage stats:\n");
1667         fprintf(StatFp,
1668                         "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
1669                         (long int) elapse_t.tv_sec - Save_t.tv_sec,
1670                         (long int) elapse_t.tv_usec - Save_t.tv_usec,
1671                         (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
1672                         (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
1673                         (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
1674                         (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
1675         fprintf(StatFp,
1676                         "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
1677                         (long int) user.tv_sec,
1678                         (long int) user.tv_usec,
1679                         (long int) sys.tv_sec,
1680                         (long int) sys.tv_usec);
1681 #ifdef HAVE_GETRUSAGE
1682         fprintf(StatFp,
1683                         "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
1684                         r.ru_inblock - Save_r.ru_inblock,
1685         /* they only drink coffee at dec */
1686                         r.ru_oublock - Save_r.ru_oublock,
1687                         r.ru_inblock, r.ru_oublock);
1688         fprintf(StatFp,
1689                   "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
1690                         r.ru_majflt - Save_r.ru_majflt,
1691                         r.ru_minflt - Save_r.ru_minflt,
1692                         r.ru_majflt, r.ru_minflt,
1693                         r.ru_nswap - Save_r.ru_nswap,
1694                         r.ru_nswap);
1695         fprintf(StatFp,
1696          "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
1697                         r.ru_nsignals - Save_r.ru_nsignals,
1698                         r.ru_nsignals,
1699                         r.ru_msgrcv - Save_r.ru_msgrcv,
1700                         r.ru_msgsnd - Save_r.ru_msgsnd,
1701                         r.ru_msgrcv, r.ru_msgsnd);
1702         fprintf(StatFp,
1703                  "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
1704                         r.ru_nvcsw - Save_r.ru_nvcsw,
1705                         r.ru_nivcsw - Save_r.ru_nivcsw,
1706                         r.ru_nvcsw, r.ru_nivcsw);
1707 #endif                                                  /* HAVE_GETRUSAGE */
1708         fprintf(StatFp, "! postgres usage stats:\n");
1709         PrintBufferUsage(StatFp);
1710 /*         DisplayTupleCount(StatFp); */
1711 }