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.26 1997/01/26 15:30:48 scrappy 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[])
794 char parser_input[MAX_PARSE_BUFFER];
797 bool multiplexedBackend;
798 char* hostName; /* the host name of the backend server */
799 char hostbuf[MAXHOSTNAMELEN];
801 int serverPortnum = 0;
802 int nSelected; /* number of descriptors ready from select(); */
803 int maxFd = 0; /* max file descriptor + 1 */
804 fd_set rmask, basemask;
805 FrontEnd *newFE, *currentFE = NULL;
806 int numFE = 0; /* keep track of number of active frontends */
818 extern short DebugLvl;
821 * register signal handlers.
824 pqsignal(SIGINT, die);
827 pqsignal(SIGHUP, die);
828 pqsignal(SIGTERM, die);
829 pqsignal(SIGPIPE, die);
830 pqsignal(SIGUSR1, quickdie);
831 pqsignal(SIGUSR2, Async_NotifyHandler);
832 pqsignal(SIGFPE, FloatExceptionHandler);
835 /* --------------------
837 * -------------------
840 MasterPid = getpid();
843 * parse command line arguments
846 flagC = flagQ = flagS = flagE = flagEu = ShowStats = 0;
847 ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
849 /* get hostname is either the environment variable PGHOST
851 if (!(hostName = getenv("PGHOST"))) {
852 if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
853 (void) strcpy(hostbuf, "localhost");
857 DataDir = getenv("PGDATA"); /* default */
858 multiplexedBackend = false; /* default */
860 while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iLm:MNo:P:pQSst:x:F"))
866 * set BushyPlanFlag to true.
873 * specify the size of buffer pool
876 NBuffers = atoi(optarg);
881 * don't print version string (don't know why this is 'C' --mao)
887 case 'D': /* PGDATA directory */
890 case 'd': /* debug level */
892 DebugLvl = (short)atoi(optarg);
894 DebugPrintQuery = true;
897 DebugPrintParse = true;
898 DebugPrintPlan = true;
899 DebugPrintRewrittenParsetree = true;
905 * E - echo the query the user entered
912 /* --------------------------
913 * Use european date formats.
914 * --------------------------
920 /* --------------------
922 * --------------------
929 * f - forbid generation of certain plans
933 case 's': /* seqscan */
934 _enable_seqscan_ = false;
936 case 'i': /* indexscan */
937 _enable_indexscan_ = false;
939 case 'n': /* nestloop */
940 _enable_nestloop_ = false;
942 case 'm': /* mergejoin */
943 _enable_mergesort_ = false;
945 case 'h': /* hashjoin */
946 _enable_hashjoin_ = false;
958 /* --------------------
960 * --------------------
966 /* start up a listening backend that can respond to
967 multiple front-ends. (Note: all the front-end connections
968 are still connected to a single-threaded backend. Requests
969 are FCFS. Everything is in one transaction
971 multiplexedBackend = true;
972 serverPortnum = atoi(optarg);
974 /* There was no postmaster started so the shared memory
975 ** for the shared memory table hasn't been allocated so
982 exit(PostmasterMain(argc, argv));
986 * N - Don't use newline as a query delimiter
994 * o - send output (stdout and stderr) to the given file
997 (void) strncpy(OutputFileName, optarg, MAXPGPATH);
1000 case 'p': /* started by postmaster */
1002 * p - special flag passed if backend was forked
1006 IsUnderPostmaster = true;
1011 * P - Use the passed file descriptor number as the port
1012 * on which to communicate with the user. This is ONLY
1013 * useful for debugging when fired up by the postmaster.
1016 Portfd = atoi(optarg);
1021 * Q - set Quiet mode (reduce debugging output)
1029 * S - assume stable main memory
1030 * (don't flush all pages at end transaction)
1034 SetTransactionFlushEnabled(false);
1039 * s - report usage statistics (timings) after each query
1048 * tell postgres to report usage statistics (timings) for
1051 * -tpa[rser] = print stats for parser time of each query
1052 * -tpl[anner] = print stats for planner time of each query
1053 * -te[xecutor] = print stats for executor time of each query
1054 * caution: -s can not be used together with -t.
1058 switch (optarg[0]) {
1059 case 'p': if (optarg[1] == 'a')
1060 ShowParserStats = 1;
1061 else if (optarg[1] == 'l')
1062 ShowPlannerStats = 1;
1066 case 'e': ShowExecutorStats = 1; break;
1067 default: errs++; break;
1072 #if 0 /* planner/xfunc.h */
1073 /* control joey hellerstein's expensive function optimization */
1076 fprintf(stderr, "only one -x flag is allowed\n");
1080 if (strcmp(optarg, "off") == 0)
1081 XfuncMode = XFUNC_OFF;
1082 else if (strcmp(optarg, "nor") == 0)
1083 XfuncMode = XFUNC_NOR;
1084 else if (strcmp(optarg, "nopull") == 0)
1085 XfuncMode = XFUNC_NOPULL;
1086 else if (strcmp(optarg, "nopm") == 0)
1087 XfuncMode = XFUNC_NOPM;
1088 else if (strcmp(optarg, "pullall") == 0)
1089 XfuncMode = XFUNC_PULLALL;
1090 else if (strcmp(optarg, "wait") == 0)
1091 XfuncMode = XFUNC_WAIT;
1093 fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
1101 * default: bad command line option
1108 * get user name and pathname and check command line validity
1112 userName = GetPgUserName();
1114 if (FindBackend(pg_pathname, argv[0]) < 0)
1115 elog(FATAL, "%s: could not locate executable, bailing out...",
1118 if (errs || argc - optind > 1) {
1121 } else if (argc - optind == 1) {
1122 DBName = argv[optind];
1123 } else if ((DBName = userName) == NULL) {
1124 fprintf(stderr, "%s: USER undefined and no database specified\n",
1130 (ShowParserStats || ShowPlannerStats || ShowExecutorStats)) {
1131 fprintf(stderr, "-s can not be used together with -t.\n");
1136 fprintf(stderr, "%s does not know where to find the database system "
1137 "data. You must specify the directory that contains the "
1138 "database system either by specifying the -D invocation "
1139 "option or by setting the PGDATA environment variable.\n\n",
1154 puts("\t---debug info---");
1155 printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
1156 printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
1157 printf("\tstable = %c\n", flagS ? 't' : 'f');
1158 printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
1159 printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
1160 printf("\tbufsize = %d\n", NBuffers);
1162 printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
1163 printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
1164 printf("\tDatabaseName = [%s]\n", DBName);
1165 puts("\t----------------\n");
1169 * initialize portal file descriptors
1172 if (IsUnderPostmaster == true) {
1175 "Postmaster flag set: no port number specified, use /dev/null\n");
1176 Portfd = open(NULL_DEV, O_RDWR, 0666);
1182 if ((status = WSAStartup(MAKEWORD(1,1), &WSAData)) == 0)
1183 (void) printf("%s\nInitializing WinSock: %s\n", WSAData.szDescription, WSAData.szSystemStatus);
1185 fprintf(stderr, "Error initializing WinSock: %d is the err", status);
1190 if (multiplexedBackend) {
1191 if (serverPortnum == 0 ||
1192 StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
1194 fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
1200 sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
1206 FD_SET(serverSock, &basemask);
1208 frontendList = DLNewList();
1209 /* add the original FrontEnd to the list */
1210 if (IsUnderPostmaster == true) {
1211 FrontEnd *fe = malloc(sizeof(FrontEnd));
1213 FD_SET(Portfd, &basemask);
1214 maxFd = Max(serverSock,Portfd) + 1;
1216 fe->fn_connected = true;
1218 fe->fn_Pfout = Pfout;
1219 fe->fn_done = false;
1220 (fe->fn_port).sock = Portfd;
1221 DLAddHead(frontendList, DLNewElem(fe));
1225 maxFd = serverSock + 1;
1229 if (IsUnderPostmaster || multiplexedBackend)
1230 whereToSendOutput = Remote;
1232 whereToSendOutput = Debug;
1234 SetProcessingMode(InitProcessing);
1238 puts("\tInitPostgres()..");
1245 InitPostgres(DBName);
1248 * if an exception is encountered, processing resumes here
1249 * so we abort the current transaction and start a new one.
1250 * This must be done after we initialize the slave backends
1251 * so that the slaves signal the master to abort the transaction
1252 * rather than calling AbortCurrentTransaction() themselves.
1254 * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
1260 pqsignal(SIGHUP, handle_warn);
1262 if (sigsetjmp(Warn_restart, 1) != 0) {
1264 if (setjmp(Warn_restart) != 0) {
1271 printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
1273 memset(parser_input, 0, MAX_PARSE_BUFFER);
1275 AbortCurrentTransaction();
1280 * POSTGRES main processing loop begins here
1283 if (IsUnderPostmaster == false) {
1284 puts("\nPOSTGRES backend interactive interface");
1285 puts("$Revision: 1.26 $ $Date: 1997/01/26 15:30:48 $");
1289 * if stable main memory is assumed (-S flag is set), it is necessary
1290 * to flush all dirty shared buffers before exit
1294 if (!TransactionFlushEnabled())
1295 on_exitpg(FlushBufferPool, (caddr_t) 0);
1299 if (multiplexedBackend) {
1303 memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
1304 nSelected = select(maxFd, &rmask,0,0,0);
1306 if (nSelected < 0) {
1308 if (errno == EINTR) continue;
1309 fprintf(stderr,"postgres: multiplexed backend select failed\n");
1312 if (FD_ISSET(serverSock, &rmask)) {
1313 /* new connection pending on our well-known port's socket */
1314 newFE = (FrontEnd*) malloc (sizeof(FrontEnd));
1315 memset(newFE, 0, sizeof(FrontEnd));
1316 newFE->fn_connected = false;
1317 newFE->fn_done = false;
1318 newPort = &(newFE->fn_port);
1319 if (StreamConnection(serverSock,newPort) != STATUS_OK) {
1320 StreamClose(newPort->sock);
1324 DLAddHead(frontendList, DLNewElem(newFE));
1326 newFd = newPort->sock;
1327 if (newFd >= maxFd) maxFd = newFd + 1;
1328 FD_SET(newFd, &rmask);
1329 FD_SET(newFd, &basemask);
1331 FD_CLR(serverSock, &rmask);
1334 } /* if FD_ISSET(serverSock) */
1336 /* if we get here, it means that the serverSocket was not the one
1337 selected. Instead, one of the front ends was selected.
1339 curr = DLGetHead(frontendList);
1341 FrontEnd *fe = (FrontEnd*)DLE_VAL(curr);
1342 Port *port = &(fe->fn_port);
1344 /* this is lifted from postmaster.c */
1345 if (FD_ISSET(port->sock, &rmask)) {
1346 if (fe->fn_connected == false) {
1347 /* we have a message from a new frontEnd */
1348 status = PacketReceive(port, &port->buf, NON_BLOCKING);
1349 if (status == STATUS_OK) {
1350 fe->fn_connected = true;
1351 pq_init(port->sock);
1353 fe->fn_Pfout = Pfout;
1356 fprintf(stderr,"Multiplexed backend: error in reading packets from %d\n", port->sock);
1358 else /* we have a query from an existing, active FrontEnd */
1361 Pfout = fe->fn_Pfout;
1367 curr = DLGetSucc(curr);
1373 curr = DLGetSucc(curr);
1377 * (1) read a command.
1380 memset(parser_input, 0, MAX_PARSE_BUFFER);
1382 firstchar = ReadCommand(parser_input, multiplexedBackend);
1383 /* process the command */
1384 switch (firstchar) {
1386 * 'F' indicates a fastpath call.
1387 * XXX HandleFunctionRequest
1391 IsEmptyQuery = false;
1393 /* start an xact for this function invocation */
1396 printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1399 StartTransactionCommand();
1400 HandleFunctionRequest();
1404 * 'Q' indicates a user query
1410 if ( strspn(parser_input," \t\n") == strlen(parser_input)) {
1412 * if there is nothing in the input buffer, don't bother
1413 * trying to parse and execute anything..
1416 IsEmptyQuery = true;
1419 * otherwise, process the input string.
1422 IsEmptyQuery = false;
1426 /* start an xact for this query */
1429 printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
1431 StartTransactionCommand();
1433 pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
1441 * 'X' means that the frontend is closing down the socket
1445 IsEmptyQuery = true;
1446 if (multiplexedBackend) {
1447 FD_CLR(currentFE->fn_port.sock, &basemask);
1448 currentFE->fn_done = true;
1455 elog(WARN,"unknown frontend message was recieved");
1459 * (3) commit the current transaction
1461 * Note: if we had an empty input buffer, then we didn't
1462 * call pg_eval, so we don't bother to commit this transaction.
1465 if (! IsEmptyQuery) {
1468 printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
1470 CommitTransactionCommand();
1473 if (IsUnderPostmaster || multiplexedBackend)
1474 NullCommand(Remote);
1477 } /* infinite for-loop */
1484 #include "rusagestub.h"
1485 #else /* NEED_RUSAGE */
1486 #include <sys/resource.h>
1487 #endif /* NEED_RUSAGE */
1489 struct rusage Save_r;
1490 struct timeval Save_t;
1496 getrusage(RUSAGE_SELF, &Save_r);
1497 gettimeofday(&Save_t, &tz);
1499 /* ResetTupleCount(); */
1505 struct timeval user, sys;
1506 struct timeval elapse_t;
1510 getrusage(RUSAGE_SELF, &r);
1511 gettimeofday(&elapse_t, &tz);
1512 memmove((char *)&user, (char *)&r.ru_utime, sizeof(user));
1513 memmove((char *)&sys, (char *)&r.ru_stime,sizeof(sys));
1514 if (elapse_t.tv_usec < Save_t.tv_usec) {
1516 elapse_t.tv_usec += 1000000;
1518 if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) {
1519 r.ru_utime.tv_sec--;
1520 r.ru_utime.tv_usec += 1000000;
1522 if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec) {
1523 r.ru_stime.tv_sec--;
1524 r.ru_stime.tv_usec += 1000000;
1528 * the only stats we don't show here are for memory usage -- i can't
1529 * figure out how to interpret the relevant fields in the rusage
1530 * struct, and they change names across o/s platforms, anyway.
1531 * if you can figure out what the entries mean, you can somehow
1532 * extract resident set size, shared text size, and unshared data
1536 fprintf(StatFp, "! system usage stats:\n");
1538 "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
1539 (long int) elapse_t.tv_sec - Save_t.tv_sec,
1540 (long int) elapse_t.tv_usec - Save_t.tv_usec,
1541 (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
1542 (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
1543 (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
1544 (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
1546 "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
1547 (long int) user.tv_sec,
1548 (long int) user.tv_usec,
1549 (long int) sys.tv_sec,
1550 (long int) sys.tv_usec);
1553 "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
1554 r.ru_inblock - Save_r.ru_inblock,
1555 /* they only drink coffee at dec */
1556 r.ru_oublock - Save_r.ru_oublock,
1557 r.ru_inblock, r.ru_oublock);
1559 "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
1560 r.ru_majflt - Save_r.ru_majflt,
1561 r.ru_minflt - Save_r.ru_minflt,
1562 r.ru_majflt, r.ru_minflt,
1563 r.ru_nswap - Save_r.ru_nswap,
1566 "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
1567 r.ru_nsignals - Save_r.ru_nsignals,
1569 r.ru_msgrcv - Save_r.ru_msgrcv,
1570 r.ru_msgsnd - Save_r.ru_msgsnd,
1571 r.ru_msgrcv, r.ru_msgsnd);
1573 "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
1574 r.ru_nvcsw - Save_r.ru_nvcsw,
1575 r.ru_nivcsw - Save_r.ru_nivcsw,
1576 r.ru_nvcsw, r.ru_nivcsw);
1577 #endif /* NEED_RUSAGE */
1578 fprintf(StatFp, "! postgres usage stats:\n");
1579 PrintBufferUsage(StatFp);
1580 /* DisplayTupleCount(StatFp); */