1 /*-------------------------------------------------------------------------
4 * POSTGRES C Backend Interface
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.25 1997/01/14 08:05:26 bryanh Exp $
13 * this is the "main" module of the postgres backend and
14 * hence the main module of the "traffic cop".
16 *-------------------------------------------------------------------------
26 #include <sys/types.h>
28 #include <sys/param.h> /* for MAXHOSTNAMELEN on most */
29 #ifndef MAXHOSTNAMELEN
30 #include <netdb.h> /* for MAXHOSTNAMELEN on some */
34 #include <sys/select.h>
39 #include "miscadmin.h"
40 #include "catalog/catname.h"
41 #include "access/xact.h"
43 #include "lib/dllist.h"
45 #include "parser/catalog_utils.h"
46 #include "parser/parse_query.h" /* for MakeTimeRange() */
47 #include "commands/async.h"
48 #include "tcop/tcopprot.h" /* where declarations for this file go */
49 #include "optimizer/planner.h"
51 #include "tcop/tcopprot.h"
52 #include "tcop/tcopdebug.h"
54 #include "executor/execdebug.h"
55 #include "executor/executor.h"
56 #include "nodes/relation.h"
58 #include "optimizer/cost.h"
59 #include "optimizer/planner.h"
61 #include "optimizer/xfunc.h"
63 #include "optimizer/prep.h"
64 #include "nodes/plannodes.h"
66 #include "storage/bufmgr.h"
68 #include "utils/palloc.h"
69 #include "utils/rel.h"
71 #include "nodes/pg_list.h"
72 #include "tcop/dest.h"
73 #include "nodes/memnodes.h"
74 #include "utils/mcxt.h"
75 #include "tcop/pquery.h"
76 #include "tcop/utility.h"
77 #include "tcop/fastpath.h"
79 #include "libpq/libpq.h"
80 #include "libpq/pqsignal.h"
81 #include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
87 static bool DebugPrintQuery = false;
88 static bool DebugPrintPlan = false;
89 static bool DebugPrintParse = false;
90 static bool DebugPrintRewrittenParsetree = false;
91 /*static bool EnableRewrite = true; , never changes why have it*/
92 CommandDest whereToSendOutput;
94 extern int lockingOff;
100 static int ShowStats;
101 static bool IsEmptyQuery = false;
103 char relname[80]; /* current relation name */
105 #if defined(WIN32) || defined(next)
106 jmp_buf Warn_restart;
107 #define sigsetjmp(x,y) setjmp(x)
108 #define siglongjmp longjmp
110 sigjmp_buf Warn_restart;
111 #endif /*defined(WIN32) || defined(next) */
116 static int EchoQuery = 0; /* default don't echo */
118 char pg_pathname[256];
119 static int ShowParserStats;
120 static int ShowPlannerStats;
121 int ShowExecutorStats;
124 typedef struct frontend {
127 FILE *fn_Pfin; /* the input fd */
128 FILE *fn_Pfout; /* the output fd */
129 bool fn_done; /* set after the frontend closes its connection */
132 static Dllist* frontendList;
135 * people who want to use EOF should #define DONTUSENEWLINE in
139 #ifndef TCOP_DONTUSENEWLINE
140 int UseNewLine = 1; /* Use newlines query delimiters (the default) */
142 int UseNewLine = 0; /* Use EOF as query delimiters */
143 #endif /* TCOP_DONTUSENEWLINE */
146 * bushy tree plan flag: if true planner will generate bushy-tree
150 int BushyPlanFlag = 0; /* default to false -- consider only left-deep trees */
153 ** Flags for expensive function optimization -- JMH 3/9/92
159 * Note: _exec_repeat_ defaults to 1 but may be changed
160 * by a DEBUG command. If you set this to a large
161 * number N, run a single query, and then set it
162 * back to 1 and run N queries, you can get an idea
163 * of how much time is being spent in the parser and
164 * planner b/c in the first case this overhead only
165 * happens once. -cim 6/9/91
168 int _exec_repeat_ = 1;
170 /* ----------------------------------------------------------------
171 * decls for routines only used in this file
172 * ----------------------------------------------------------------
174 static char InteractiveBackend(char *inBuf);
175 static char SocketBackend(char *inBuf, bool multiplexedBackend);
176 static char ReadCommand(char *inBuf, bool multiplexedBackend);
179 /* ----------------------------------------------------------------
180 * routines to obtain user input
181 * ----------------------------------------------------------------
185 * InteractiveBackend() is called for user interactive connections
186 * the string entered by the user is placed in its parameter inBuf.
191 InteractiveBackend(char *inBuf)
193 char *stuff = inBuf; /* current place in input buffer */
194 int c; /* character read from getc() */
195 bool end = false; /* end-of-input flag */
196 bool backslashSeen = false; /* have we seen a \ ? */
199 * display a prompt and obtain input from the user
207 * if we are using \n as a delimiter, then read
208 * characters until the \n.
211 while ( (c = getc(stdin)) != EOF) {
217 /* keep the newline character */
222 } else if (c == '\\')
223 backslashSeen = true;
225 backslashSeen = false;
234 * otherwise read characters until EOF.
237 while ( (c = getc(stdin)) != EOF )
240 if ( stuff == inBuf )
245 if (!Quiet) puts("EOF");
251 * otherwise we have a user query so process it.
258 * if the query echo flag was given, print the query..
262 printf("query is: %s\n", inBuf);
268 * SocketBackend() Is called for frontend-backend connections
270 * If the input is a query (case 'Q') then the string entered by
271 * the user is placed in its parameter inBuf.
273 * If the input is a fastpath function call (case 'F') then
274 * the function call is processed in HandleFunctionRequest().
275 * (now called from PostgresMain())
280 SocketBackend(char *inBuf, bool multiplexedBackend)
286 * get input from the frontend
289 (void) strcpy(qtype, "?");
290 if (pq_getnchar(qtype,0,1) == EOF) {
292 * when front-end applications quits/dies
295 if (multiplexedBackend) {
304 * 'Q': user entered a query
308 pq_getstr(inBuf, MAX_PARSE_BUFFER);
313 * 'F': calling user/system functions
317 pq_getstr(inBuf, MAX_PARSE_BUFFER);/* ignore the rest of the line */
322 * 'X': frontend is exiting
330 * otherwise we got garbage from the frontend.
332 * XXX are we certain that we want to do an elog(FATAL) here?
337 elog(FATAL, "Socket command type %c unknown\n", *qtype);
344 * ReadCommand reads a command from either the frontend or
345 * standard input, places it in inBuf, and returns a char
346 * representing whether the string is a 'Q'uery or a 'F'astpath
351 ReadCommand(char *inBuf, bool multiplexedBackend)
353 if (IsUnderPostmaster || multiplexedBackend)
354 return SocketBackend(inBuf, multiplexedBackend);
356 return InteractiveBackend(inBuf);
360 pg_plan(char *query_string, /* string to execute */
361 Oid *typev, /* argument types */
362 int nargs, /* number of arguments */
363 QueryTreeList **queryListP, /* pointer to the parse trees */
364 CommandDest dest) /* where results should go */
366 QueryTreeList *querytree_list;
368 List *plan_list = NIL;
371 QueryTreeList *new_list;
372 List *rewritten = NIL;
376 * (1) parse the request string into a list of parse trees
382 querytree_list = parser(query_string, typev, nargs);
384 if (ShowParserStats) {
385 fprintf(stderr, "! Parser Stats:\n");
389 /* new_list holds the rewritten queries */
390 new_list = (QueryTreeList*)malloc(sizeof(QueryTreeList));
391 new_list->len = querytree_list->len;
392 new_list->qtrees = (Query**)malloc(new_list->len * sizeof(Query*));
395 * (2) rewrite the queries, as necessary
398 j = 0; /* counter for the new_list, new_list can be longer than
399 old list as a result of rewrites */
400 for (i=0;i<querytree_list->len;i++) {
401 querytree = querytree_list->qtrees[i];
404 /* don't rewrite utilites */
405 if (querytree->commandType == CMD_UTILITY) {
406 new_list->qtrees[j++] = querytree;
410 if ( DebugPrintQuery == true ) {
411 printf("\n---- \tquery is:\n%s\n",query_string);
416 if ( DebugPrintParse == true ) {
417 printf("\n---- \tparser outputs :\n");
418 nodeDisplay(querytree);
422 /* rewrite queries (retrieve, append, delete, replace) */
423 rewritten = QueryRewrite(querytree);
424 if (rewritten != NULL) {
426 len = length(rewritten);
428 new_list->qtrees[j++] = (Query*)lfirst(rewritten);
430 /* rewritten queries are longer than original query */
431 /* grow the new_list to accommodate */
432 new_list->len += len - 1; /* - 1 because originally we
433 allocated one space for the query */
434 new_list->qtrees = realloc(new_list->qtrees,
435 new_list->len * sizeof(Query*));
437 new_list->qtrees[j++] = (Query*)nth(k, rewritten);
442 /* we're done with the original lists, free it */
443 free(querytree_list->qtrees);
444 free(querytree_list);
446 querytree_list = new_list;
449 * Fix time range quals
450 * this _must_ go here, because it must take place after rewrites
451 * ( if they take place ) so that time quals are usable by the executor
453 * Also, need to frob the range table entries here to plan union
454 * queries for archived relations.
457 for (i=0;i<querytree_list->len;i++) {
461 querytree = querytree_list->qtrees[i];
464 * utilities don't have time ranges
467 if (querytree->commandType == CMD_UTILITY)
470 rt = querytree->rtable;
473 RangeTblEntry *rte = lfirst(l);
474 TimeRange *timequal = rte->timeRange;
477 int timecode = (rte->timeRange->endDate == NULL)? 0 : 1;
479 rte->timeQual = makeTimeRange(rte->timeRange->startDate,
480 rte->timeRange->endDate,
483 rte->timeQual = NULL;
487 /* check for archived relations */
491 if (DebugPrintRewrittenParsetree == true) {
492 printf("\n---- \tafter rewriting:\n");
494 for (i=0; i<querytree_list->len; i++) {
495 print(querytree_list->qtrees[i]);
500 for (i=0; i<querytree_list->len;i++) {
501 querytree = querytree_list->qtrees[i];
504 * For each query that isn't a utility invocation,
508 if (querytree->commandType != CMD_UTILITY) {
510 if (IsAbortedTransactionBlockState()) {
512 * the EndCommand() stuff is to tell the frontend
513 * that the command ended. -cim 6/1/90
516 char *tag = "*ABORT STATE*";
517 EndCommand(tag, dest);
519 elog(NOTICE, "(transaction aborted): %s",
520 "queries ignored until END");
522 *queryListP = (QueryTreeList*)NULL;
526 if (ShowPlannerStats) ResetUsage();
527 plan = planner(querytree);
528 if (ShowPlannerStats) {
529 fprintf(stderr, "! Planner Stats:\n");
532 plan_list = lappend(plan_list, plan);
533 #ifdef INDEXSCAN_PATCH
535 * Print plan if debugging.
536 * This has been moved here to get debugging output
537 * also for queries in functions. DZ - 27-8-1996
540 if ( DebugPrintPlan == true ) {
541 printf("\n---- \tplan is :\n");
547 #ifdef FUNC_UTIL_PATCH
549 * If the command is an utility append a null plan. This is
550 * needed to keep the plan_list aligned with the querytree_list
551 * or the function executor will crash. DZ - 30-8-1996
554 plan_list = lappend(plan_list, NULL);
560 *queryListP = querytree_list;
565 /* ----------------------------------------------------------------
568 * Takes a querystring, runs the parser/utilities or
569 * parser/planner/executor over it as necessary
570 * Begin Transaction Should have been called before this
571 * and CommitTransaction After this is called
572 * This is strictly because we do not allow for nested xactions.
574 * NON-OBVIOUS-RESTRICTIONS
575 * this function _MUST_ allocate a new "parsetree" each time,
576 * since it may be stored in a named portal and should not
579 * ----------------------------------------------------------------
583 pg_eval(char *query_string, char **argv, Oid *typev, int nargs)
585 pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
589 pg_eval_dest(char *query_string, /* string to execute */
590 char **argv, /* arguments */
591 Oid *typev, /* argument types */
592 int nargs, /* number of arguments */
593 CommandDest dest) /* where results should go */
599 QueryTreeList *querytree_list;
601 /* plan the queries */
602 plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
604 /* pg_plan could have failed */
605 if (querytree_list == NULL)
608 for (i=0;i<querytree_list->len;i++) {
609 querytree = querytree_list->qtrees[i];
611 #ifdef FUNC_UTIL_PATCH
613 * Advance on the plan_list in every case. Now the plan_list
614 * has the same length of the querytree_list. DZ - 30-8-1996
616 plan = (Plan *) lfirst(plan_list);
617 plan_list = lnext(plan_list);
619 if (querytree->commandType == CMD_UTILITY) {
621 * process utility functions (create, destroy, etc..)
623 * Note: we do not check for the transaction aborted state
624 * because that is done in ProcessUtility.
629 printf("\tProcessUtility() at %s\n", ctime(&tim));
632 ProcessUtility(querytree->utilityStmt, dest);
635 #ifndef FUNC_UTIL_PATCH
637 * Moved before the if. DZ - 30-8-1996
639 plan = (Plan *) lfirst(plan_list);
640 plan_list = lnext(plan_list);
643 #ifdef INDEXSCAN_PATCH
645 * Print moved in pg_plan. DZ - 27-8-1996
649 * print plan if debugging
652 if ( DebugPrintPlan == true ) {
653 printf("\n---- plan is :\n");
663 if (ShowExecutorStats)
666 for (j = 0; j < _exec_repeat_; j++) {
669 printf("\tProcessQuery() at %s\n", ctime(&tim));
671 ProcessQuery(querytree, plan, argv, typev, nargs, dest);
674 if (ShowExecutorStats) {
675 fprintf(stderr, "! Executor Stats:\n");
680 * In a query block, we want to increment the command counter
681 * between queries so that the effects of early queries are
682 * visible to subsequent ones.
686 CommandCounterIncrement();
689 free(querytree_list->qtrees);
690 free(querytree_list);
693 /* --------------------------------
694 * signal handler routines used in PostgresMain()
696 * handle_warn() is used to catch kill(getpid(),1) which
697 * occurs when elog(WARN) is called.
699 * quickdie() occurs when signalled by the postmaster, some backend
700 * has bought the farm we need to stop what we're doing and exit.
702 * die() preforms an orderly cleanup via ExitPostgres()
703 * --------------------------------
707 handle_warn(SIGNAL_ARGS)
709 siglongjmp(Warn_restart, 1);
713 quickdie(SIGNAL_ARGS)
715 elog(NOTICE, "I have been signalled by the postmaster.");
716 elog(NOTICE, "Some backend process has died unexpectedly and possibly");
717 elog(NOTICE, "corrupted shared memory. The current transaction was");
718 elog(NOTICE, "aborted, and I am going to exit. Please resend the");
719 elog(NOTICE, "last query. -- The postgres backend");
722 * DO NOT ExitPostgres(0) -- we're here because shared memory may be
723 * corrupted, so we don't want to flush any shared state to stable
724 * storage. Just nail the windows shut and get out of town.
736 /* signal handler for floating point exception */
738 FloatExceptionHandler(SIGNAL_ARGS)
740 elog(WARN, "floating point exception! the last floating point operation eit\
741 her exceeded legal ranges or was a divide by zero");
745 static void usage(char* progname)
748 "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
750 fprintf(stderr,"\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
751 fprintf(stderr, " b: consider bushy plan trees during optimization\n");
752 fprintf(stderr, " B: set number of buffers in buffer pool\n");
753 fprintf(stderr, " C: supress version info\n");
754 fprintf(stderr, " d: set debug level\n");
755 fprintf(stderr, " E: echo query before execution\n");
756 fprintf(stderr, " F: turn off fsync\n");
757 fprintf(stderr, " f: forbid plantype generation\n");
758 fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
759 fprintf(stderr, " L: turn off locking\n");
760 fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
761 fprintf(stderr, " M: start as postmaster\n");
762 fprintf(stderr, " N: don't use newline as query delimiter\n");
763 fprintf(stderr, " o: send stdout and stderr to given filename \n");
764 fprintf(stderr, " p: backend started by postmaster\n");
765 fprintf(stderr, " P: set port file descriptor\n");
766 fprintf(stderr, " Q: suppress informational messages\n");
767 fprintf(stderr, " S: assume stable main memory\n");
768 fprintf(stderr, " s: show stats after each query\n");
769 fprintf(stderr, " t: trace component execution times\n");
770 fprintf(stderr, " T: execute all possible plans for each query\n");
771 fprintf(stderr, " x: control expensive function optimization\n");
774 /* ----------------------------------------------------------------
777 * all backends, interactive or otherwise start here
778 * ----------------------------------------------------------------
781 PostgresMain(int argc, char *argv[])
793 char parser_input[MAX_PARSE_BUFFER];
796 bool multiplexedBackend;
797 char* hostName; /* the host name of the backend server */
798 char hostbuf[MAXHOSTNAMELEN];
800 int serverPortnum = 0;
801 int nSelected; /* number of descriptors ready from select(); */
802 int maxFd = 0; /* max file descriptor + 1 */
803 fd_set rmask, basemask;
804 FrontEnd *newFE, *currentFE = NULL;
805 int numFE = 0; /* keep track of number of active frontends */
817 extern short DebugLvl;
820 * register signal handlers.
823 pqsignal(SIGINT, die);
826 pqsignal(SIGHUP, die);
827 pqsignal(SIGTERM, die);
828 pqsignal(SIGPIPE, die);
829 pqsignal(SIGUSR1, quickdie);
830 pqsignal(SIGUSR2, Async_NotifyHandler);
831 pqsignal(SIGFPE, FloatExceptionHandler);
834 /* --------------------
836 * -------------------
839 MasterPid = getpid();
842 * parse command line arguments
845 flagC = flagQ = flagS = flagE = ShowStats = 0;
846 ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
848 /* get hostname is either the environment variable PGHOST
850 if (!(hostName = getenv("PGHOST"))) {
851 if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
852 (void) strcpy(hostbuf, "localhost");
856 DataDir = getenv("PGDATA"); /* default */
857 multiplexedBackend = false; /* default */
859 while ((flag = getopt(argc, argv, "B:bCD:d:Ef:iLm:MNo:P:pQSst:x:F"))
865 * set BushyPlanFlag to true.
872 * specify the size of buffer pool
875 NBuffers = atoi(optarg);
880 * don't print version string (don't know why this is 'C' --mao)
886 case 'D': /* PGDATA directory */
889 case 'd': /* debug level */
891 DebugLvl = (short)atoi(optarg);
893 DebugPrintQuery = true;
896 DebugPrintParse = true;
897 DebugPrintPlan = true;
898 DebugPrintRewrittenParsetree = true;
904 * E - echo the query the user entered
911 /* --------------------
913 * --------------------
920 * f - forbid generation of certain plans
924 case 's': /* seqscan */
925 _enable_seqscan_ = false;
927 case 'i': /* indexscan */
928 _enable_indexscan_ = false;
930 case 'n': /* nestloop */
931 _enable_nestloop_ = false;
933 case 'm': /* mergejoin */
934 _enable_mergesort_ = false;
936 case 'h': /* hashjoin */
937 _enable_hashjoin_ = false;
949 /* --------------------
951 * --------------------
957 /* start up a listening backend that can respond to
958 multiple front-ends. (Note: all the front-end connections
959 are still connected to a single-threaded backend. Requests
960 are FCFS. Everything is in one transaction
962 multiplexedBackend = true;
963 serverPortnum = atoi(optarg);
965 /* There was no postmaster started so the shared memory
966 ** for the shared memory table hasn't been allocated so
973 exit(PostmasterMain(argc, argv));
977 * N - Don't use newline as a query delimiter
985 * o - send output (stdout and stderr) to the given file
988 (void) strncpy(OutputFileName, optarg, MAXPGPATH);
991 case 'p': /* started by postmaster */
993 * p - special flag passed if backend was forked
997 IsUnderPostmaster = true;
1002 * P - Use the passed file descriptor number as the port
1003 * on which to communicate with the user. This is ONLY
1004 * useful for debugging when fired up by the postmaster.
1007 Portfd = atoi(optarg);
1012 * Q - set Quiet mode (reduce debugging output)
1020 * S - assume stable main memory
1021 * (don't flush all pages at end transaction)
1025 SetTransactionFlushEnabled(false);
1030 * s - report usage statistics (timings) after each query
1039 * tell postgres to report usage statistics (timings) for
1042 * -tpa[rser] = print stats for parser time of each query
1043 * -tpl[anner] = print stats for planner time of each query
1044 * -te[xecutor] = print stats for executor time of each query
1045 * caution: -s can not be used together with -t.
1049 switch (optarg[0]) {
1050 case 'p': if (optarg[1] == 'a')
1051 ShowParserStats = 1;
1052 else if (optarg[1] == 'l')
1053 ShowPlannerStats = 1;
1057 case 'e': ShowExecutorStats = 1; break;
1058 default: errs++; break;
1063 #if 0 /* planner/xfunc.h */
1064 /* control joey hellerstein's expensive function optimization */
1067 fprintf(stderr, "only one -x flag is allowed\n");
1071 if (strcmp(optarg, "off") == 0)
1072 XfuncMode = XFUNC_OFF;
1073 else if (strcmp(optarg, "nor") == 0)
1074 XfuncMode = XFUNC_NOR;
1075 else if (strcmp(optarg, "nopull") == 0)
1076 XfuncMode = XFUNC_NOPULL;
1077 else if (strcmp(optarg, "nopm") == 0)
1078 XfuncMode = XFUNC_NOPM;
1079 else if (strcmp(optarg, "pullall") == 0)
1080 XfuncMode = XFUNC_PULLALL;
1081 else if (strcmp(optarg, "wait") == 0)
1082 XfuncMode = XFUNC_WAIT;
1084 fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
1092 * default: bad command line option
1099 * get user name and pathname and check command line validity
1103 userName = GetPgUserName();
1105 if (FindBackend(pg_pathname, argv[0]) < 0)
1106 elog(FATAL, "%s: could not locate executable, bailing out...",
1109 if (errs || argc - optind > 1) {
1112 } else if (argc - optind == 1) {
1113 DBName = argv[optind];
1114 } else if ((DBName = userName) == NULL) {
1115 fprintf(stderr, "%s: USER undefined and no database specified\n",
1121 (ShowParserStats || ShowPlannerStats || ShowExecutorStats)) {
1122 fprintf(stderr, "-s can not be used together with -t.\n");
1127 fprintf(stderr, "%s does not know where to find the database system "
1128 "data. You must specify the directory that contains the "
1129 "database system either by specifying the -D invocation "
1130 "option or by setting the PGDATA environment variable.\n\n",
1144 puts("\t---debug info---");
1145 printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
1146 printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
1147 printf("\tstable = %c\n", flagS ? 't' : 'f');
1148 printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
1149 printf("\tbufsize = %d\n", NBuffers);
1151 printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
1152 printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
1153 printf("\tDatabaseName = [%s]\n", DBName);
1154 puts("\t----------------\n");
1158 * initialize portal file descriptors
1161 if (IsUnderPostmaster == true) {
1164 "Postmaster flag set: no port number specified, use /dev/null\n");
1165 Portfd = open(NULL_DEV, O_RDWR, 0666);
1171 if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0)
1172 (void) printf("%s\nInitializing WinSock: %s\n", WSAData.szDescription, WSAData.szSystemStatus);
1174 fprintf(stderr, "Error initializing WinSock: %d is the err", status);
1179 if (multiplexedBackend) {
1180 if (serverPortnum == 0 ||
1181 StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
1183 fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
1189 sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
1195 FD_SET(serverSock, &basemask);
1197 frontendList = DLNewList();
1198 /* add the original FrontEnd to the list */
1199 if (IsUnderPostmaster == true) {
1200 FrontEnd *fe = malloc(sizeof(FrontEnd));
1202 FD_SET(Portfd, &basemask);
1203 maxFd = Max(serverSock,Portfd) + 1;
1205 fe->fn_connected = true;
1207 fe->fn_Pfout = Pfout;
1208 fe->fn_done = false;
1209 (fe->fn_port).sock = Portfd;
1210 DLAddHead(frontendList, DLNewElem(fe));
1214 maxFd = serverSock + 1;
1218 if (IsUnderPostmaster || multiplexedBackend)
1219 whereToSendOutput = Remote;
1221 whereToSendOutput = Debug;
1223 SetProcessingMode(InitProcessing);
1227 puts("\tInitPostgres()..");
1234 InitPostgres(DBName);
1237 * if an exception is encountered, processing resumes here
1238 * so we abort the current transaction and start a new one.
1239 * This must be done after we initialize the slave backends
1240 * so that the slaves signal the master to abort the transaction
1241 * rather than calling AbortCurrentTransaction() themselves.
1243 * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
1249 pqsignal(SIGHUP, handle_warn);
1251 if (sigsetjmp(Warn_restart, 1) != 0) {
1253 if (setjmp(Warn_restart) != 0) {
1260 printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
1262 memset(parser_input, 0, MAX_PARSE_BUFFER);
1264 AbortCurrentTransaction();
1269 * POSTGRES main processing loop begins here
1272 if (IsUnderPostmaster == false) {
1273 puts("\nPOSTGRES backend interactive interface");
1274 puts("$Revision: 1.25 $ $Date: 1997/01/14 08:05:26 $");
1278 * if stable main memory is assumed (-S flag is set), it is necessary
1279 * to flush all dirty shared buffers before exit
1283 if (!TransactionFlushEnabled())
1284 on_exitpg(FlushBufferPool, (caddr_t) 0);
1288 if (multiplexedBackend) {
1292 memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
1293 nSelected = select(maxFd, &rmask,0,0,0);
1295 if (nSelected < 0) {
1297 if (errno == EINTR) continue;
1298 fprintf(stderr,"postgres: multiplexed backend select failed\n");
1301 if (FD_ISSET(serverSock, &rmask)) {
1302 /* new connection pending on our well-known port's socket */
1303 newFE = (FrontEnd*) malloc (sizeof(FrontEnd));
1304 memset(newFE, 0, sizeof(FrontEnd));
1305 newFE->fn_connected = false;
1306 newFE->fn_done = false;
1307 newPort = &(newFE->fn_port);
1308 if (StreamConnection(serverSock,newPort) != STATUS_OK) {
1309 StreamClose(newPort->sock);
1313 DLAddHead(frontendList, DLNewElem(newFE));
1315 newFd = newPort->sock;
1316 if (newFd >= maxFd) maxFd = newFd + 1;
1317 FD_SET(newFd, &rmask);
1318 FD_SET(newFd, &basemask);
1320 FD_CLR(serverSock, &rmask);
1323 } /* if FD_ISSET(serverSock) */
1325 /* if we get here, it means that the serverSocket was not the one
1326 selected. Instead, one of the front ends was selected.
1328 curr = DLGetHead(frontendList);
1330 FrontEnd *fe = (FrontEnd*)DLE_VAL(curr);
1331 Port *port = &(fe->fn_port);
1333 /* this is lifted from postmaster.c */
1334 if (FD_ISSET(port->sock, &rmask)) {
1335 if (fe->fn_connected == false) {
1336 /* we have a message from a new frontEnd */
1337 status = PacketReceive(port, &port->buf, NON_BLOCKING);
1338 if (status == STATUS_OK) {
1339 fe->fn_connected = true;
1340 pq_init(port->sock);
1342 fe->fn_Pfout = Pfout;
1345 fprintf(stderr,"Multiplexed backend: error in reading packets from %d\n", port->sock);
1347 else /* we have a query from an existing, active FrontEnd */
1350 Pfout = fe->fn_Pfout;
1356 curr = DLGetSucc(curr);
1362 curr = DLGetSucc(curr);
1366 * (1) read a command.
1369 memset(parser_input, 0, MAX_PARSE_BUFFER);
1371 firstchar = ReadCommand(parser_input, multiplexedBackend);
1372 /* process the command */
1373 switch (firstchar) {
1375 * 'F' indicates a fastpath call.
1376 * XXX HandleFunctionRequest
1380 IsEmptyQuery = false;
1382 /* start an xact for this function invocation */
1385 printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1388 StartTransactionCommand();
1389 HandleFunctionRequest();
1393 * 'Q' indicates a user query
1399 if ( strspn(parser_input," \t\n") == strlen(parser_input)) {
1401 * if there is nothing in the input buffer, don't bother
1402 * trying to parse and execute anything..
1405 IsEmptyQuery = true;
1408 * otherwise, process the input string.
1411 IsEmptyQuery = false;
1415 /* start an xact for this query */
1418 printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1420 StartTransactionCommand();
1422 pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
1430 * 'X' means that the frontend is closing down the socket
1434 IsEmptyQuery = true;
1435 if (multiplexedBackend) {
1436 FD_CLR(currentFE->fn_port.sock, &basemask);
1437 currentFE->fn_done = true;
1444 elog(WARN,"unknown frontend message was recieved");
1448 * (3) commit the current transaction
1450 * Note: if we had an empty input buffer, then we didn't
1451 * call pg_eval, so we don't bother to commit this transaction.
1454 if (! IsEmptyQuery) {
1457 printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
1459 CommitTransactionCommand();
1462 if (IsUnderPostmaster || multiplexedBackend)
1463 NullCommand(Remote);
1466 } /* infinite for-loop */
1473 #include "rusagestub.h"
1474 #else /* NEED_RUSAGE */
1475 #include <sys/resource.h>
1476 #endif /* NEED_RUSAGE */
1478 struct rusage Save_r;
1479 struct timeval Save_t;
1485 getrusage(RUSAGE_SELF, &Save_r);
1486 gettimeofday(&Save_t, &tz);
1488 /* ResetTupleCount(); */
1494 struct timeval user, sys;
1495 struct timeval elapse_t;
1499 getrusage(RUSAGE_SELF, &r);
1500 gettimeofday(&elapse_t, &tz);
1501 memmove((char *)&user, (char *)&r.ru_utime, sizeof(user));
1502 memmove((char *)&sys, (char *)&r.ru_stime,sizeof(sys));
1503 if (elapse_t.tv_usec < Save_t.tv_usec) {
1505 elapse_t.tv_usec += 1000000;
1507 if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) {
1508 r.ru_utime.tv_sec--;
1509 r.ru_utime.tv_usec += 1000000;
1511 if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec) {
1512 r.ru_stime.tv_sec--;
1513 r.ru_stime.tv_usec += 1000000;
1517 * the only stats we don't show here are for memory usage -- i can't
1518 * figure out how to interpret the relevant fields in the rusage
1519 * struct, and they change names across o/s platforms, anyway.
1520 * if you can figure out what the entries mean, you can somehow
1521 * extract resident set size, shared text size, and unshared data
1525 fprintf(StatFp, "! system usage stats:\n");
1527 "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
1528 (long int) elapse_t.tv_sec - Save_t.tv_sec,
1529 (long int) elapse_t.tv_usec - Save_t.tv_usec,
1530 (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
1531 (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
1532 (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
1533 (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
1535 "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
1536 (long int) user.tv_sec,
1537 (long int) user.tv_usec,
1538 (long int) sys.tv_sec,
1539 (long int) sys.tv_usec);
1542 "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
1543 r.ru_inblock - Save_r.ru_inblock,
1544 /* they only drink coffee at dec */
1545 r.ru_oublock - Save_r.ru_oublock,
1546 r.ru_inblock, r.ru_oublock);
1548 "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
1549 r.ru_majflt - Save_r.ru_majflt,
1550 r.ru_minflt - Save_r.ru_minflt,
1551 r.ru_majflt, r.ru_minflt,
1552 r.ru_nswap - Save_r.ru_nswap,
1555 "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
1556 r.ru_nsignals - Save_r.ru_nsignals,
1558 r.ru_msgrcv - Save_r.ru_msgrcv,
1559 r.ru_msgsnd - Save_r.ru_msgsnd,
1560 r.ru_msgrcv, r.ru_msgsnd);
1562 "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
1563 r.ru_nvcsw - Save_r.ru_nvcsw,
1564 r.ru_nivcsw - Save_r.ru_nivcsw,
1565 r.ru_nvcsw, r.ru_nivcsw);
1566 #endif /* NEED_RUSAGE */
1567 fprintf(StatFp, "! postgres usage stats:\n");
1568 PrintBufferUsage(StatFp);
1569 /* DisplayTupleCount(StatFp); */