aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop/postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r--src/backend/tcop/postgres.c2789
1 files changed, 1462 insertions, 1327 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index cd658704f03..f70d30434bb 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1,17 +1,17 @@
/*-------------------------------------------------------------------------
*
* postgres.c--
- * POSTGRES C Backend Interface
+ * POSTGRES C Backend Interface
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.42 1997/08/19 21:34:04 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.43 1997/09/07 04:49:33 momjian Exp $
*
* NOTES
- * this is the "main" module of the postgres backend and
- * hence the main module of the "traffic cop".
+ * this is the "main" module of the postgres backend and
+ * hence the main module of the "traffic cop".
*
*-------------------------------------------------------------------------
*/
@@ -25,17 +25,17 @@
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
-#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
+#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
-#include <netdb.h> /* for MAXHOSTNAMELEN on some */
+#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
-#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
+#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
#include <sys/socket.h>
#endif
#include <errno.h>
#ifdef aix
#include <sys/select.h>
-#endif /* aix */
+#endif /* aix */
#include "postgres.h"
@@ -46,9 +46,9 @@
#include "lib/dllist.h"
#include "parser/catalog_utils.h"
-#include "parser/parse_query.h" /* for MakeTimeRange() */
+#include "parser/parse_query.h" /* for MakeTimeRange() */
#include "commands/async.h"
-#include "tcop/tcopprot.h" /* where declarations for this file go */
+#include "tcop/tcopprot.h" /* where declarations for this file go */
#include "optimizer/planner.h"
#include "tcop/tcopprot.h"
@@ -88,1488 +88,1623 @@
#include "libpq/libpq.h"
#include "libpq/pqsignal.h"
-#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
+#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
-static void quickdie(SIGNAL_ARGS);
+static void quickdie(SIGNAL_ARGS);
/* ----------------
- * global variables
+ * global variables
* ----------------
*/
-static bool DebugPrintQuery = false;
-static bool DebugPrintPlan = false;
-static bool DebugPrintParse = false;
-static bool DebugPrintRewrittenParsetree = false;
-/*static bool EnableRewrite = true; , never changes why have it*/
-CommandDest whereToSendOutput;
+static bool DebugPrintQuery = false;
+static bool DebugPrintPlan = false;
+static bool DebugPrintParse = false;
+static bool DebugPrintRewrittenParsetree = false;
+
+/*static bool EnableRewrite = true; , never changes why have it*/
+CommandDest whereToSendOutput;
#ifdef LOCK_MGR_DEBUG
-extern int lockDebug;
+extern int lockDebug;
+
#endif
-extern int lockingOff;
-extern int NBuffers;
+extern int lockingOff;
+extern int NBuffers;
-int dontExecute = 0;
-static int ShowStats;
-static bool IsEmptyQuery = false;
+int dontExecute = 0;
+static int ShowStats;
+static bool IsEmptyQuery = false;
-char relname[80]; /* current relation name */
+char relname[80]; /* current relation name */
#if defined(nextstep)
-jmp_buf Warn_restart;
-#define sigsetjmp(x,y) setjmp(x)
+jmp_buf Warn_restart;
+
+#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
#else
-sigjmp_buf Warn_restart;
-#endif /* defined(nextstep) */
-int InWarn;
-
-extern int NBuffers;
-
-static int EchoQuery = 0; /* default don't echo */
-time_t tim;
-char pg_pathname[256];
-static int ShowParserStats;
-static int ShowPlannerStats;
-int ShowExecutorStats;
-FILE *StatFp;
-
-typedef struct frontend {
- bool fn_connected;
- Port fn_port;
- FILE *fn_Pfin; /* the input fd */
- FILE *fn_Pfout; /* the output fd */
- bool fn_done; /* set after the frontend closes its connection */
-} FrontEnd;
-
-static Dllist* frontendList;
+sigjmp_buf Warn_restart;
+
+#endif /* defined(nextstep) */
+int InWarn;
+
+extern int NBuffers;
+
+static int EchoQuery = 0; /* default don't echo */
+time_t tim;
+char pg_pathname[256];
+static int ShowParserStats;
+static int ShowPlannerStats;
+int ShowExecutorStats;
+FILE *StatFp;
+
+typedef struct frontend
+{
+ bool fn_connected;
+ Port fn_port;
+ FILE *fn_Pfin; /* the input fd */
+ FILE *fn_Pfout; /* the output fd */
+ bool fn_done; /* set after the frontend closes its
+ * connection */
+} FrontEnd;
+
+static Dllist *frontendList;
/* ----------------
- * people who want to use EOF should #define DONTUSENEWLINE in
- * tcop/tcopdebug.h
+ * people who want to use EOF should #define DONTUSENEWLINE in
+ * tcop/tcopdebug.h
* ----------------
*/
#ifndef TCOP_DONTUSENEWLINE
-int UseNewLine = 1; /* Use newlines query delimiters (the default) */
+int UseNewLine = 1; /* Use newlines query delimiters (the
+ * default) */
+
#else
-int UseNewLine = 0; /* Use EOF as query delimiters */
-#endif /* TCOP_DONTUSENEWLINE */
+int UseNewLine = 0; /* Use EOF as query delimiters */
+
+#endif /* TCOP_DONTUSENEWLINE */
/* ----------------
- * bushy tree plan flag: if true planner will generate bushy-tree
- * plans
+ * bushy tree plan flag: if true planner will generate bushy-tree
+ * plans
* ----------------
*/
-int BushyPlanFlag = 0; /* default to false -- consider only left-deep trees */
+int BushyPlanFlag = 0; /* default to false -- consider
+ * only left-deep trees */
/*
** Flags for expensive function optimization -- JMH 3/9/92
*/
-int XfuncMode = 0;
+int XfuncMode = 0;
/*
* ----------------
- * Note: _exec_repeat_ defaults to 1 but may be changed
- * by a DEBUG command. If you set this to a large
- * number N, run a single query, and then set it
- * back to 1 and run N queries, you can get an idea
- * of how much time is being spent in the parser and
- * planner b/c in the first case this overhead only
- * happens once. -cim 6/9/91
+ * Note: _exec_repeat_ defaults to 1 but may be changed
+ * by a DEBUG command. If you set this to a large
+ * number N, run a single query, and then set it
+ * back to 1 and run N queries, you can get an idea
+ * of how much time is being spent in the parser and
+ * planner b/c in the first case this overhead only
+ * happens once. -cim 6/9/91
* ----------------
*/
-int _exec_repeat_ = 1;
+int _exec_repeat_ = 1;
/* ----------------------------------------------------------------
- * decls for routines only used in this file
+ * decls for routines only used in this file
* ----------------------------------------------------------------
*/
-static char InteractiveBackend(char *inBuf);
-static char SocketBackend(char *inBuf, bool multiplexedBackend);
-static char ReadCommand(char *inBuf, bool multiplexedBackend);
+static char InteractiveBackend(char *inBuf);
+static char SocketBackend(char *inBuf, bool multiplexedBackend);
+static char ReadCommand(char *inBuf, bool multiplexedBackend);
/* ----------------------------------------------------------------
- * routines to obtain user input
+ * routines to obtain user input
* ----------------------------------------------------------------
*/
/* ----------------
- * InteractiveBackend() is called for user interactive connections
- * the string entered by the user is placed in its parameter inBuf.
+ * InteractiveBackend() is called for user interactive connections
+ * the string entered by the user is placed in its parameter inBuf.
* ----------------
*/
static char
InteractiveBackend(char *inBuf)
{
- char *stuff = inBuf; /* current place in input buffer */
- int c; /* character read from getc() */
- bool end = false; /* end-of-input flag */
- bool backslashSeen = false; /* have we seen a \ ? */
-
- /* ----------------
- * display a prompt and obtain input from the user
- * ----------------
- */
- printf("> ");
-
- for (;;) {
- if (UseNewLine) {
- /* ----------------
- * if we are using \n as a delimiter, then read
- * characters until the \n.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF) {
- if (c == '\n') {
- if (backslashSeen) {
- stuff--;
- continue;
- } else {
- /* keep the newline character */
- *stuff++ = '\n';
- *stuff++ = '\0';
- break;
- }
- } else if (c == '\\')
- backslashSeen = true;
- else
- backslashSeen = false;
-
- *stuff++ = (char)c;
- }
-
- if (c == EOF)
- end = true;
- } else {
- /* ----------------
- * otherwise read characters until EOF.
- * ----------------
- */
- while ( (c = getc(stdin)) != EOF )
- *stuff++ = (char)c;
-
- if ( stuff == inBuf )
- end = true;
- }
-
- if (end) {
- if (!Quiet) puts("EOF");
- IsEmptyQuery = true;
- exitpg(0);
- }
-
- /* ----------------
- * otherwise we have a user query so process it.
- * ----------------
- */
- break;
- }
-
- /* ----------------
- * if the query echo flag was given, print the query..
- * ----------------
- */
- if (EchoQuery)
- printf("query is: %s\n", inBuf);
-
- return('Q');
+ char *stuff = inBuf; /* current place in input buffer */
+ int c; /* character read from getc() */
+ bool end = false;/* end-of-input flag */
+ bool backslashSeen = false; /* have we seen a \ ? */
+
+ /* ----------------
+ * display a prompt and obtain input from the user
+ * ----------------
+ */
+ printf("> ");
+
+ for (;;)
+ {
+ if (UseNewLine)
+ {
+ /* ----------------
+ * if we are using \n as a delimiter, then read
+ * characters until the \n.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ {
+ if (c == '\n')
+ {
+ if (backslashSeen)
+ {
+ stuff--;
+ continue;
+ }
+ else
+ {
+ /* keep the newline character */
+ *stuff++ = '\n';
+ *stuff++ = '\0';
+ break;
+ }
+ }
+ else if (c == '\\')
+ backslashSeen = true;
+ else
+ backslashSeen = false;
+
+ *stuff++ = (char) c;
+ }
+
+ if (c == EOF)
+ end = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise read characters until EOF.
+ * ----------------
+ */
+ while ((c = getc(stdin)) != EOF)
+ *stuff++ = (char) c;
+
+ if (stuff == inBuf)
+ end = true;
+ }
+
+ if (end)
+ {
+ if (!Quiet)
+ puts("EOF");
+ IsEmptyQuery = true;
+ exitpg(0);
+ }
+
+ /* ----------------
+ * otherwise we have a user query so process it.
+ * ----------------
+ */
+ break;
+ }
+
+ /* ----------------
+ * if the query echo flag was given, print the query..
+ * ----------------
+ */
+ if (EchoQuery)
+ printf("query is: %s\n", inBuf);
+
+ return ('Q');
}
/* ----------------
- * SocketBackend() Is called for frontend-backend connections
+ * SocketBackend() Is called for frontend-backend connections
*
- * If the input is a query (case 'Q') then the string entered by
- * the user is placed in its parameter inBuf.
+ * If the input is a query (case 'Q') then the string entered by
+ * the user is placed in its parameter inBuf.
*
- * If the input is a fastpath function call (case 'F') then
- * the function call is processed in HandleFunctionRequest().
- * (now called from PostgresMain())
+ * If the input is a fastpath function call (case 'F') then
+ * the function call is processed in HandleFunctionRequest().
+ * (now called from PostgresMain())
* ----------------
*/
static char
SocketBackend(char *inBuf, bool multiplexedBackend)
{
- char qtype[2];
- char result = '\0';
-
- /* ----------------
- * get input from the frontend
- * ----------------
- */
- strcpy(qtype, "?");
- if (pq_getnchar(qtype,0,1) == EOF) {
- /* ------------
- * when front-end applications quits/dies
- * ------------
- */
- if (multiplexedBackend) {
- return 'X';
- }
- else
- exitpg(0);
- }
-
- switch(*qtype) {
- /* ----------------
- * 'Q': user entered a query
- * ----------------
- */
- case 'Q':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);
- result = 'Q';
- break;
-
- /* ----------------
- * 'F': calling user/system functions
- * ----------------
- */
- case 'F':
- pq_getstr(inBuf, MAX_PARSE_BUFFER);/* ignore the rest of the line */
- result = 'F';
- break;
-
- /* ----------------
- * 'X': frontend is exiting
- * ----------------
- */
- case 'X':
- result = 'X';
- break;
-
- /* ----------------
- * otherwise we got garbage from the frontend.
- *
- * XXX are we certain that we want to do an elog(FATAL) here?
- * -cim 1/24/90
- * ----------------
- */
- default:
- elog(FATAL, "Socket command type %c unknown\n", *qtype);
- break;
- }
- return result;
+ char qtype[2];
+ char result = '\0';
+
+ /* ----------------
+ * get input from the frontend
+ * ----------------
+ */
+ strcpy(qtype, "?");
+ if (pq_getnchar(qtype, 0, 1) == EOF)
+ {
+ /* ------------
+ * when front-end applications quits/dies
+ * ------------
+ */
+ if (multiplexedBackend)
+ {
+ return 'X';
+ }
+ else
+ exitpg(0);
+ }
+
+ switch (*qtype)
+ {
+ /* ----------------
+ * 'Q': user entered a query
+ * ----------------
+ */
+ case 'Q':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER);
+ result = 'Q';
+ break;
+
+ /* ----------------
+ * 'F': calling user/system functions
+ * ----------------
+ */
+ case 'F':
+ pq_getstr(inBuf, MAX_PARSE_BUFFER); /* ignore the rest of the
+ * line */
+ result = 'F';
+ break;
+
+ /* ----------------
+ * 'X': frontend is exiting
+ * ----------------
+ */
+ case 'X':
+ result = 'X';
+ break;
+
+ /* ----------------
+ * otherwise we got garbage from the frontend.
+ *
+ * XXX are we certain that we want to do an elog(FATAL) here?
+ * -cim 1/24/90
+ * ----------------
+ */
+ default:
+ elog(FATAL, "Socket command type %c unknown\n", *qtype);
+ break;
+ }
+ return result;
}
/* ----------------
- * ReadCommand reads a command from either the frontend or
- * standard input, places it in inBuf, and returns a char
- * representing whether the string is a 'Q'uery or a 'F'astpath
- * call.
+ * ReadCommand reads a command from either the frontend or
+ * standard input, places it in inBuf, and returns a char
+ * representing whether the string is a 'Q'uery or a 'F'astpath
+ * call.
* ----------------
*/
static char
ReadCommand(char *inBuf, bool multiplexedBackend)
{
- if (IsUnderPostmaster || multiplexedBackend)
- return SocketBackend(inBuf, multiplexedBackend);
- else
- return InteractiveBackend(inBuf);
+ if (IsUnderPostmaster || multiplexedBackend)
+ return SocketBackend(inBuf, multiplexedBackend);
+ else
+ return InteractiveBackend(inBuf);
}
-List *
-pg_plan(char *query_string, /* string to execute */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- QueryTreeList **queryListP, /* pointer to the parse trees */
- CommandDest dest) /* where results should go */
+List *
+pg_plan(char *query_string, /* string to execute */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ QueryTreeList ** queryListP, /* pointer to the parse trees */
+ CommandDest dest) /* where results should go */
{
- QueryTreeList *querytree_list;
- int i;
- List *plan_list = NIL;
- Plan *plan;
- int j;
- QueryTreeList *new_list;
- List *rewritten = NIL;
- Query* querytree;
-
- /* ----------------
- * (1) parse the request string into a list of parse trees
- * ----------------
- */
- if (ShowParserStats)
- ResetUsage();
-
- querytree_list = parser(query_string, typev, nargs);
-
- if (ShowParserStats) {
- fprintf(stderr, "! Parser Stats:\n");
- ShowUsage();
- }
-
- /* new_list holds the rewritten queries */
- new_list = (QueryTreeList*)malloc(sizeof(QueryTreeList));
- new_list->len = querytree_list->len;
- new_list->qtrees = (Query**)malloc(new_list->len * sizeof(Query*));
-
- /* ----------------
- * (2) rewrite the queries, as necessary
- * ----------------
- */
- j = 0; /* counter for the new_list, new_list can be longer than
- old list as a result of rewrites */
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
-
- /* don't rewrite utilites */
- if (querytree->commandType == CMD_UTILITY) {
- new_list->qtrees[j++] = querytree;
- continue;
- }
-
- if ( DebugPrintQuery == true ) {
- printf("\n---- \tquery is:\n%s\n",query_string);
- printf("\n");
- fflush(stdout);
- }
-
- if ( DebugPrintParse == true ) {
- printf("\n---- \tparser outputs :\n");
- nodeDisplay(querytree);
- printf("\n");
- }
-
- /* rewrite queries (retrieve, append, delete, replace) */
- rewritten = QueryRewrite(querytree);
- if (rewritten != NULL) {
- int len, k;
- len = length(rewritten);
- if (len == 1)
- new_list->qtrees[j++] = (Query*)lfirst(rewritten);
- else {
- /* rewritten queries are longer than original query */
- /* grow the new_list to accommodate */
- new_list->len += len - 1; /* - 1 because originally we
- allocated one space for the query */
- new_list->qtrees = realloc(new_list->qtrees,
- new_list->len * sizeof(Query*));
- for (k=0;k<len;k++)
- new_list->qtrees[j++] = (Query*)nth(k, rewritten);
- }
- }
- }
-
- /* we're done with the original lists, free it */
- free(querytree_list->qtrees);
- free(querytree_list);
-
- querytree_list = new_list;
-
- /* ----------------
- * Fix time range quals
- * this _must_ go here, because it must take place after rewrites
- * ( if they take place ) so that time quals are usable by the executor
- *
- * Also, need to frob the range table entries here to plan union
- * queries for archived relations.
- * ----------------
- */
- for (i=0;i<querytree_list->len;i++) {
- List *l;
- List *rt = NULL;
-
- querytree = querytree_list->qtrees[i];
-
- /* ----------------
- * utilities don't have time ranges
- * ----------------
- */
- if (querytree->commandType == CMD_UTILITY)
- continue;
-
- rt = querytree->rtable;
-
- foreach (l, rt) {
- RangeTblEntry *rte = lfirst(l);
- TimeRange *timequal = rte->timeRange;
-
- if (timequal) {
- int timecode = (rte->timeRange->endDate == NULL)? 0 : 1;
-
- rte->timeQual = makeTimeRange(rte->timeRange->startDate,
- rte->timeRange->endDate,
- timecode);
- }else {
- rte->timeQual = NULL;
- }
- }
-
- /* check for archived relations */
- plan_archive(rt);
- }
-
- if (DebugPrintRewrittenParsetree == true) {
- printf("\n---- \tafter rewriting:\n");
-
- for (i=0; i<querytree_list->len; i++) {
- print(querytree_list->qtrees[i]);
- printf("\n");
- }
- }
-
- for (i=0; i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
- /*
- * For each query that isn't a utility invocation,
- * generate a plan.
- */
-
- if (querytree->commandType != CMD_UTILITY) {
-
- if (IsAbortedTransactionBlockState()) {
- /* ----------------
- * the EndCommand() stuff is to tell the frontend
- * that the command ended. -cim 6/1/90
- * ----------------
- */
- char *tag = "*ABORT STATE*";
- EndCommand(tag, dest);
-
- elog(NOTICE, "(transaction aborted): %s",
- "queries ignored until END");
-
- *queryListP = (QueryTreeList*)NULL;
- return (List*)NULL;
- }
-
- if (ShowPlannerStats) ResetUsage();
- plan = planner(querytree);
- if (ShowPlannerStats) {
- fprintf(stderr, "! Planner Stats:\n");
- ShowUsage();
- }
- plan_list = lappend(plan_list, plan);
+ QueryTreeList *querytree_list;
+ int i;
+ List *plan_list = NIL;
+ Plan *plan;
+ int j;
+ QueryTreeList *new_list;
+ List *rewritten = NIL;
+ Query *querytree;
+
+ /* ----------------
+ * (1) parse the request string into a list of parse trees
+ * ----------------
+ */
+ if (ShowParserStats)
+ ResetUsage();
+
+ querytree_list = parser(query_string, typev, nargs);
+
+ if (ShowParserStats)
+ {
+ fprintf(stderr, "! Parser Stats:\n");
+ ShowUsage();
+ }
+
+ /* new_list holds the rewritten queries */
+ new_list = (QueryTreeList *) malloc(sizeof(QueryTreeList));
+ new_list->len = querytree_list->len;
+ new_list->qtrees = (Query **) malloc(new_list->len * sizeof(Query *));
+
+ /* ----------------
+ * (2) rewrite the queries, as necessary
+ * ----------------
+ */
+ j = 0; /* counter for the new_list, new_list can
+ * be longer than old list as a result of
+ * rewrites */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+
+ /* don't rewrite utilites */
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ new_list->qtrees[j++] = querytree;
+ continue;
+ }
+
+ if (DebugPrintQuery == true)
+ {
+ printf("\n---- \tquery is:\n%s\n", query_string);
+ printf("\n");
+ fflush(stdout);
+ }
+
+ if (DebugPrintParse == true)
+ {
+ printf("\n---- \tparser outputs :\n");
+ nodeDisplay(querytree);
+ printf("\n");
+ }
+
+ /* rewrite queries (retrieve, append, delete, replace) */
+ rewritten = QueryRewrite(querytree);
+ if (rewritten != NULL)
+ {
+ int len,
+ k;
+
+ len = length(rewritten);
+ if (len == 1)
+ new_list->qtrees[j++] = (Query *) lfirst(rewritten);
+ else
+ {
+ /* rewritten queries are longer than original query */
+ /* grow the new_list to accommodate */
+ new_list->len += len - 1; /* - 1 because originally
+ * we allocated one space
+ * for the query */
+ new_list->qtrees = realloc(new_list->qtrees,
+ new_list->len * sizeof(Query *));
+ for (k = 0; k < len; k++)
+ new_list->qtrees[j++] = (Query *) nth(k, rewritten);
+ }
+ }
+ }
+
+ /* we're done with the original lists, free it */
+ free(querytree_list->qtrees);
+ free(querytree_list);
+
+ querytree_list = new_list;
+
+ /* ----------------
+ * Fix time range quals
+ * this _must_ go here, because it must take place after rewrites
+ * ( if they take place ) so that time quals are usable by the executor
+ *
+ * Also, need to frob the range table entries here to plan union
+ * queries for archived relations.
+ * ----------------
+ */
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ List *l;
+ List *rt = NULL;
+
+ querytree = querytree_list->qtrees[i];
+
+ /* ----------------
+ * utilities don't have time ranges
+ * ----------------
+ */
+ if (querytree->commandType == CMD_UTILITY)
+ continue;
+
+ rt = querytree->rtable;
+
+ foreach(l, rt)
+ {
+ RangeTblEntry *rte = lfirst(l);
+ TimeRange *timequal = rte->timeRange;
+
+ if (timequal)
+ {
+ int timecode = (rte->timeRange->endDate == NULL) ? 0 : 1;
+
+ rte->timeQual = makeTimeRange(rte->timeRange->startDate,
+ rte->timeRange->endDate,
+ timecode);
+ }
+ else
+ {
+ rte->timeQual = NULL;
+ }
+ }
+
+ /* check for archived relations */
+ plan_archive(rt);
+ }
+
+ if (DebugPrintRewrittenParsetree == true)
+ {
+ printf("\n---- \tafter rewriting:\n");
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ print(querytree_list->qtrees[i]);
+ printf("\n");
+ }
+ }
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
+ /*
+ * For each query that isn't a utility invocation, generate a
+ * plan.
+ */
+
+ if (querytree->commandType != CMD_UTILITY)
+ {
+
+ if (IsAbortedTransactionBlockState())
+ {
+ /* ----------------
+ * the EndCommand() stuff is to tell the frontend
+ * that the command ended. -cim 6/1/90
+ * ----------------
+ */
+ char *tag = "*ABORT STATE*";
+
+ EndCommand(tag, dest);
+
+ elog(NOTICE, "(transaction aborted): %s",
+ "queries ignored until END");
+
+ *queryListP = (QueryTreeList *) NULL;
+ return (List *) NULL;
+ }
+
+ if (ShowPlannerStats)
+ ResetUsage();
+ plan = planner(querytree);
+ if (ShowPlannerStats)
+ {
+ fprintf(stderr, "! Planner Stats:\n");
+ ShowUsage();
+ }
+ plan_list = lappend(plan_list, plan);
#ifdef INDEXSCAN_PATCH
- /* ----------------
- * Print plan if debugging.
- * This has been moved here to get debugging output
- * also for queries in functions. DZ - 27-8-1996
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- \tplan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * Print plan if debugging.
+ * This has been moved here to get debugging output
+ * also for queries in functions. DZ - 27-8-1996
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- \tplan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
- }
+ }
#ifdef FUNC_UTIL_PATCH
- /*
- * If the command is an utility append a null plan. This is
- * needed to keep the plan_list aligned with the querytree_list
- * or the function executor will crash. DZ - 30-8-1996
- */
- else {
- plan_list = lappend(plan_list, NULL);
- }
+
+ /*
+ * If the command is an utility append a null plan. This is needed
+ * to keep the plan_list aligned with the querytree_list or the
+ * function executor will crash. DZ - 30-8-1996
+ */
+ else
+ {
+ plan_list = lappend(plan_list, NULL);
+ }
#endif
- }
-
- if (queryListP)
- *queryListP = querytree_list;
-
- return (plan_list);
+ }
+
+ if (queryListP)
+ *queryListP = querytree_list;
+
+ return (plan_list);
}
/* ----------------------------------------------------------------
- * pg_eval()
- *
- * Takes a querystring, runs the parser/utilities or
- * parser/planner/executor over it as necessary
- * Begin Transaction Should have been called before this
- * and CommitTransaction After this is called
- * This is strictly because we do not allow for nested xactions.
+ * pg_eval()
+ *
+ * Takes a querystring, runs the parser/utilities or
+ * parser/planner/executor over it as necessary
+ * Begin Transaction Should have been called before this
+ * and CommitTransaction After this is called
+ * This is strictly because we do not allow for nested xactions.
*
- * NON-OBVIOUS-RESTRICTIONS
- * this function _MUST_ allocate a new "parsetree" each time,
- * since it may be stored in a named portal and should not
- * change its value.
+ * NON-OBVIOUS-RESTRICTIONS
+ * this function _MUST_ allocate a new "parsetree" each time,
+ * since it may be stored in a named portal and should not
+ * change its value.
*
* ----------------------------------------------------------------
*/
void
-pg_eval(char *query_string, char **argv, Oid *typev, int nargs)
+pg_eval(char *query_string, char **argv, Oid * typev, int nargs)
{
- pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
+ pg_eval_dest(query_string, argv, typev, nargs, whereToSendOutput);
}
void
-pg_eval_dest(char *query_string, /* string to execute */
- char **argv, /* arguments */
- Oid *typev, /* argument types */
- int nargs, /* number of arguments */
- CommandDest dest) /* where results should go */
+pg_eval_dest(char *query_string,/* string to execute */
+ char **argv, /* arguments */
+ Oid * typev, /* argument types */
+ int nargs, /* number of arguments */
+ CommandDest dest) /* where results should go */
{
- List *plan_list;
- Plan *plan;
- Query *querytree;
- int i,j;
- QueryTreeList *querytree_list;
-
- /* plan the queries */
- plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
-
- /* pg_plan could have failed */
- if (querytree_list == NULL)
- return;
-
- for (i=0;i<querytree_list->len;i++) {
- querytree = querytree_list->qtrees[i];
-
+ List *plan_list;
+ Plan *plan;
+ Query *querytree;
+ int i,
+ j;
+ QueryTreeList *querytree_list;
+
+ /* plan the queries */
+ plan_list = pg_plan(query_string, typev, nargs, &querytree_list, dest);
+
+ /* pg_plan could have failed */
+ if (querytree_list == NULL)
+ return;
+
+ for (i = 0; i < querytree_list->len; i++)
+ {
+ querytree = querytree_list->qtrees[i];
+
#ifdef FUNC_UTIL_PATCH
- /*
- * Advance on the plan_list in every case. Now the plan_list
- * has the same length of the querytree_list. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Advance on the plan_list in every case. Now the plan_list has
+ * the same length of the querytree_list. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
- if (querytree->commandType == CMD_UTILITY) {
- /* ----------------
- * process utility functions (create, destroy, etc..)
- *
- * Note: we do not check for the transaction aborted state
- * because that is done in ProcessUtility.
- * ----------------
- */
- if (! Quiet) {
- time(&tim);
- printf("\tProcessUtility() at %s\n", ctime(&tim));
- }
-
- ProcessUtility(querytree->utilityStmt, dest);
-
- } else {
+ if (querytree->commandType == CMD_UTILITY)
+ {
+ /* ----------------
+ * process utility functions (create, destroy, etc..)
+ *
+ * Note: we do not check for the transaction aborted state
+ * because that is done in ProcessUtility.
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessUtility() at %s\n", ctime(&tim));
+ }
+
+ ProcessUtility(querytree->utilityStmt, dest);
+
+ }
+ else
+ {
#ifndef FUNC_UTIL_PATCH
- /*
- * Moved before the if. DZ - 30-8-1996
- */
- plan = (Plan *) lfirst(plan_list);
- plan_list = lnext(plan_list);
+
+ /*
+ * Moved before the if. DZ - 30-8-1996
+ */
+ plan = (Plan *) lfirst(plan_list);
+ plan_list = lnext(plan_list);
#endif
-
+
#ifdef INDEXSCAN_PATCH
- /*
- * Print moved in pg_plan. DZ - 27-8-1996
- */
+
+ /*
+ * Print moved in pg_plan. DZ - 27-8-1996
+ */
#else
- /* ----------------
- * print plan if debugging
- * ----------------
- */
- if ( DebugPrintPlan == true ) {
- printf("\n---- plan is :\n");
- nodeDisplay(plan);
- printf("\n");
- }
+ /* ----------------
+ * print plan if debugging
+ * ----------------
+ */
+ if (DebugPrintPlan == true)
+ {
+ printf("\n---- plan is :\n");
+ nodeDisplay(plan);
+ printf("\n");
+ }
#endif
-
- /* ----------------
- * execute the plan
- *
- */
- if (ShowExecutorStats)
- ResetUsage();
-
- for (j = 0; j < _exec_repeat_; j++) {
- if (! Quiet) {
- time(&tim);
- printf("\tProcessQuery() at %s\n", ctime(&tim));
- }
- ProcessQuery(querytree, plan, argv, typev, nargs, dest);
- }
-
- if (ShowExecutorStats) {
- fprintf(stderr, "! Executor Stats:\n");
- ShowUsage();
- }
- }
- /*
- * In a query block, we want to increment the command counter
- * between queries so that the effects of early queries are
- * visible to subsequent ones.
- */
-
- if (querytree_list)
- CommandCounterIncrement();
- }
-
- free(querytree_list->qtrees);
- free(querytree_list);
+
+ /* ----------------
+ * execute the plan
+ *
+ */
+ if (ShowExecutorStats)
+ ResetUsage();
+
+ for (j = 0; j < _exec_repeat_; j++)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tProcessQuery() at %s\n", ctime(&tim));
+ }
+ ProcessQuery(querytree, plan, argv, typev, nargs, dest);
+ }
+
+ if (ShowExecutorStats)
+ {
+ fprintf(stderr, "! Executor Stats:\n");
+ ShowUsage();
+ }
+ }
+
+ /*
+ * In a query block, we want to increment the command counter
+ * between queries so that the effects of early queries are
+ * visible to subsequent ones.
+ */
+
+ if (querytree_list)
+ CommandCounterIncrement();
+ }
+
+ free(querytree_list->qtrees);
+ free(querytree_list);
}
/* --------------------------------
- * signal handler routines used in PostgresMain()
+ * signal handler routines used in PostgresMain()
*
- * handle_warn() is used to catch kill(getpid(),1) which
- * occurs when elog(WARN) is called.
+ * handle_warn() is used to catch kill(getpid(),1) which
+ * occurs when elog(WARN) is called.
*
- * quickdie() occurs when signalled by the postmaster, some backend
- * has bought the farm we need to stop what we're doing and exit.
+ * quickdie() occurs when signalled by the postmaster, some backend
+ * has bought the farm we need to stop what we're doing and exit.
*
- * die() preforms an orderly cleanup via ExitPostgres()
+ * die() preforms an orderly cleanup via ExitPostgres()
* --------------------------------
*/
void
handle_warn(SIGNAL_ARGS)
{
- siglongjmp(Warn_restart, 1);
+ siglongjmp(Warn_restart, 1);
}
static void
quickdie(SIGNAL_ARGS)
{
- elog(NOTICE, "I have been signalled by the postmaster.");
- elog(NOTICE, "Some backend process has died unexpectedly and possibly");
- elog(NOTICE, "corrupted shared memory. The current transaction was");
- elog(NOTICE, "aborted, and I am going to exit. Please resend the");
- elog(NOTICE, "last query. -- The postgres backend");
-
- /*
- * DO NOT ExitPostgres(0) -- we're here because shared memory may be
- * corrupted, so we don't want to flush any shared state to stable
- * storage. Just nail the windows shut and get out of town.
- */
-
- exit (0);
+ elog(NOTICE, "I have been signalled by the postmaster.");
+ elog(NOTICE, "Some backend process has died unexpectedly and possibly");
+ elog(NOTICE, "corrupted shared memory. The current transaction was");
+ elog(NOTICE, "aborted, and I am going to exit. Please resend the");
+ elog(NOTICE, "last query. -- The postgres backend");
+
+ /*
+ * DO NOT ExitPostgres(0) -- we're here because shared memory may be
+ * corrupted, so we don't want to flush any shared state to stable
+ * storage. Just nail the windows shut and get out of town.
+ */
+
+ exit(0);
}
void
die(SIGNAL_ARGS)
{
- ExitPostgres(0);
+ ExitPostgres(0);
}
/* signal handler for floating point exception */
static void
FloatExceptionHandler(SIGNAL_ARGS)
{
- elog(WARN, "floating point exception! the last floating point operation eit\
+ elog(WARN, "floating point exception! the last floating point operation eit\
her exceeded legal ranges or was a divide by zero");
}
-static void usage(char* progname)
+static void
+usage(char *progname)
{
- fprintf(stderr,
- "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
- progname);
- fprintf(stderr,"\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
- fprintf(stderr, " b: consider bushy plan trees during optimization\n");
- fprintf(stderr, " B: set number of buffers in buffer pool\n");
- fprintf(stderr, " C: supress version info\n");
- fprintf(stderr, " d: set debug level\n");
- fprintf(stderr, " E: echo query before execution\n");
- fprintf(stderr, " e turn on European date format\n");
- fprintf(stderr, " F: turn off fsync\n");
- fprintf(stderr, " f: forbid plantype generation\n");
- fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
+ fprintf(stderr,
+ "Usage: %s [-B nbufs] [-d lvl] ] [-f plantype] \t[-m portno] [\t -o filename]\n",
+ progname);
+ fprintf(stderr, "\t[-P portno] [-t tracetype] [-x opttype] [-bCEiLFNopQSs] [dbname]\n");
+ fprintf(stderr, " b: consider bushy plan trees during optimization\n");
+ fprintf(stderr, " B: set number of buffers in buffer pool\n");
+ fprintf(stderr, " C: supress version info\n");
+ fprintf(stderr, " d: set debug level\n");
+ fprintf(stderr, " E: echo query before execution\n");
+ fprintf(stderr, " e turn on European date format\n");
+ fprintf(stderr, " F: turn off fsync\n");
+ fprintf(stderr, " f: forbid plantype generation\n");
+ fprintf(stderr, " i: don't execute the query, just show the plan tree\n");
#ifdef LOCK_MGR_DEBUG
- fprintf(stderr, " K: set locking debug level [0|1|2]\n");
+ fprintf(stderr, " K: set locking debug level [0|1|2]\n");
#endif
- fprintf(stderr, " L: turn off locking\n");
- fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
- fprintf(stderr, " M: start as postmaster\n");
- fprintf(stderr, " N: don't use newline as query delimiter\n");
- fprintf(stderr, " o: send stdout and stderr to given filename \n");
- fprintf(stderr, " p: backend started by postmaster\n");
- fprintf(stderr, " P: set port file descriptor\n");
- fprintf(stderr, " Q: suppress informational messages\n");
- fprintf(stderr, " S: set amount of sort memory available\n");
- fprintf(stderr, " s: show stats after each query\n");
- fprintf(stderr, " t: trace component execution times\n");
- fprintf(stderr, " T: execute all possible plans for each query\n");
- fprintf(stderr, " x: control expensive function optimization\n");
+ fprintf(stderr, " L: turn off locking\n");
+ fprintf(stderr, " m: set up a listening backend at portno to support multiple front-ends\n");
+ fprintf(stderr, " M: start as postmaster\n");
+ fprintf(stderr, " N: don't use newline as query delimiter\n");
+ fprintf(stderr, " o: send stdout and stderr to given filename \n");
+ fprintf(stderr, " p: backend started by postmaster\n");
+ fprintf(stderr, " P: set port file descriptor\n");
+ fprintf(stderr, " Q: suppress informational messages\n");
+ fprintf(stderr, " S: set amount of sort memory available\n");
+ fprintf(stderr, " s: show stats after each query\n");
+ fprintf(stderr, " t: trace component execution times\n");
+ fprintf(stderr, " T: execute all possible plans for each query\n");
+ fprintf(stderr, " x: control expensive function optimization\n");
}
/* ----------------------------------------------------------------
- * PostgresMain
- * postgres main loop
- * all backends, interactive or otherwise start here
+ * PostgresMain
+ * postgres main loop
+ * all backends, interactive or otherwise start here
* ----------------------------------------------------------------
*/
int
PostgresMain(int argc, char *argv[])
{
- int flagC;
- int flagQ;
- int flagE;
- int flagEu;
- int flag;
-
- char *DBName = NULL;
- int errs = 0;
-
- char firstchar;
- char parser_input[MAX_PARSE_BUFFER];
- char *userName;
-
- bool multiplexedBackend;
- char* hostName; /* the host name of the backend server */
- char hostbuf[MAXHOSTNAMELEN];
- int serverSock;
- int serverPortnum = 0;
- int nSelected; /* number of descriptors ready from select(); */
- int maxFd = 0; /* max file descriptor + 1 */
- fd_set rmask, basemask;
- FrontEnd *newFE, *currentFE = NULL;
- int numFE = 0; /* keep track of number of active frontends */
- Port *newPort;
- int newFd;
- Dlelem *curr;
- int status;
-
- extern int optind;
- extern char *optarg;
- extern short DebugLvl;
-
- /* ----------------
- * register signal handlers.
- * ----------------
- */
- pqsignal(SIGINT, die);
-
- pqsignal(SIGHUP, die);
- pqsignal(SIGTERM, die);
- pqsignal(SIGPIPE, die);
- pqsignal(SIGUSR1, quickdie);
- pqsignal(SIGUSR2, Async_NotifyHandler);
- pqsignal(SIGFPE, FloatExceptionHandler);
-
- /* --------------------
- * initialize globals
- * -------------------
- */
-
- MasterPid = getpid();
-
- /* ----------------
- * parse command line arguments
- * ----------------
- */
- flagC = flagQ = flagE = flagEu = ShowStats = 0;
- ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
+ int flagC;
+ int flagQ;
+ int flagE;
+ int flagEu;
+ int flag;
+
+ char *DBName = NULL;
+ int errs = 0;
+
+ char firstchar;
+ char parser_input[MAX_PARSE_BUFFER];
+ char *userName;
+
+ bool multiplexedBackend;
+ char *hostName; /* the host name of the backend server */
+ char hostbuf[MAXHOSTNAMELEN];
+ int serverSock;
+ int serverPortnum = 0;
+ int nSelected; /* number of descriptors ready from
+ * select(); */
+ int maxFd = 0; /* max file descriptor + 1 */
+ fd_set rmask,
+ basemask;
+ FrontEnd *newFE,
+ *currentFE = NULL;
+ int numFE = 0; /* keep track of number of active
+ * frontends */
+ Port *newPort;
+ int newFd;
+ Dlelem *curr;
+ int status;
+
+ extern int optind;
+ extern char *optarg;
+ extern short DebugLvl;
+
+ /* ----------------
+ * register signal handlers.
+ * ----------------
+ */
+ pqsignal(SIGINT, die);
+
+ pqsignal(SIGHUP, die);
+ pqsignal(SIGTERM, die);
+ pqsignal(SIGPIPE, die);
+ pqsignal(SIGUSR1, quickdie);
+ pqsignal(SIGUSR2, Async_NotifyHandler);
+ pqsignal(SIGFPE, FloatExceptionHandler);
+
+ /* --------------------
+ * initialize globals
+ * -------------------
+ */
+
+ MasterPid = getpid();
+
+ /* ----------------
+ * parse command line arguments
+ * ----------------
+ */
+ flagC = flagQ = flagE = flagEu = ShowStats = 0;
+ ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
#ifdef LOCK_MGR_DEBUG
- lockDebug = 0;
+ lockDebug = 0;
#endif
- /* get hostname is either the environment variable PGHOST
- or 'localhost' */
- if (!(hostName = getenv("PGHOST"))) {
- if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
- strcpy(hostbuf, "localhost");
- hostName = hostbuf;
- }
-
- DataDir = getenv("PGDATA"); /* default */
- multiplexedBackend = false; /* default */
-
- while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
- != EOF)
- switch (flag) {
-
- case 'b':
- /* ----------------
- * set BushyPlanFlag to true.
- * ----------------
- */
- BushyPlanFlag = 1;
- break;
- case 'B':
- /* ----------------
- * specify the size of buffer pool
- * ----------------
- */
- NBuffers = atoi(optarg);
- break;
-
- case 'C':
- /* ----------------
- * don't print version string (don't know why this is 'C' --mao)
- * ----------------
- */
- flagC = 1;
- break;
-
- case 'D': /* PGDATA directory */
- DataDir = optarg;
-
- case 'd': /* debug level */
- flagQ = 0;
- DebugLvl = (short)atoi(optarg);
- if (DebugLvl > 1)
- DebugPrintQuery = true;
- if (DebugLvl > 2)
- {
- DebugPrintParse = true;
- DebugPrintPlan = true;
- DebugPrintRewrittenParsetree = true;
- }
- break;
-
- case 'E':
- /* ----------------
- * E - echo the query the user entered
- * ----------------
- */
- flagE = 1;
- break;
-
- case 'e':
- /* --------------------------
- * Use european date formats.
- * --------------------------
- */
- flagEu = 1;
- break;
-
- case 'F':
- /* --------------------
- * turn off fsync
- * --------------------
- */
- fsyncOff = 1;
- break;
-
- case 'f':
- /* -----------------
- * f - forbid generation of certain plans
- * -----------------
- */
- switch (optarg[0]) {
- case 's': /* seqscan */
- _enable_seqscan_ = false;
- break;
- case 'i': /* indexscan */
- _enable_indexscan_ = false;
- break;
- case 'n': /* nestloop */
- _enable_nestloop_ = false;
- break;
- case 'm': /* mergejoin */
- _enable_mergesort_ = false;
- break;
- case 'h': /* hashjoin */
- _enable_hashjoin_ = false;
- break;
- default:
- errs++;
- }
- break;
-
- case 'i':
- dontExecute = 1;
- break;
-
- case 'K':
+ /*
+ * get hostname is either the environment variable PGHOST or
+ * 'localhost'
+ */
+ if (!(hostName = getenv("PGHOST")))
+ {
+ if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
+ strcpy(hostbuf, "localhost");
+ hostName = hostbuf;
+ }
+
+ DataDir = getenv("PGDATA"); /* default */
+ multiplexedBackend = false; /* default */
+
+ while ((flag = getopt(argc, argv, "B:bCD:d:Eef:iK:Lm:MNo:P:pQSst:x:F"))
+ != EOF)
+ switch (flag)
+ {
+
+ case 'b':
+ /* ----------------
+ * set BushyPlanFlag to true.
+ * ----------------
+ */
+ BushyPlanFlag = 1;
+ break;
+ case 'B':
+ /* ----------------
+ * specify the size of buffer pool
+ * ----------------
+ */
+ NBuffers = atoi(optarg);
+ break;
+
+ case 'C':
+ /* ----------------
+ * don't print version string (don't know why this is 'C' --mao)
+ * ----------------
+ */
+ flagC = 1;
+ break;
+
+ case 'D': /* PGDATA directory */
+ DataDir = optarg;
+
+ case 'd': /* debug level */
+ flagQ = 0;
+ DebugLvl = (short) atoi(optarg);
+ if (DebugLvl > 1)
+ DebugPrintQuery = true;
+ if (DebugLvl > 2)
+ {
+ DebugPrintParse = true;
+ DebugPrintPlan = true;
+ DebugPrintRewrittenParsetree = true;
+ }
+ break;
+
+ case 'E':
+ /* ----------------
+ * E - echo the query the user entered
+ * ----------------
+ */
+ flagE = 1;
+ break;
+
+ case 'e':
+ /* --------------------------
+ * Use european date formats.
+ * --------------------------
+ */
+ flagEu = 1;
+ break;
+
+ case 'F':
+ /* --------------------
+ * turn off fsync
+ * --------------------
+ */
+ fsyncOff = 1;
+ break;
+
+ case 'f':
+ /* -----------------
+ * f - forbid generation of certain plans
+ * -----------------
+ */
+ switch (optarg[0])
+ {
+ case 's': /* seqscan */
+ _enable_seqscan_ = false;
+ break;
+ case 'i': /* indexscan */
+ _enable_indexscan_ = false;
+ break;
+ case 'n': /* nestloop */
+ _enable_nestloop_ = false;
+ break;
+ case 'm': /* mergejoin */
+ _enable_mergesort_ = false;
+ break;
+ case 'h': /* hashjoin */
+ _enable_hashjoin_ = false;
+ break;
+ default:
+ errs++;
+ }
+ break;
+
+ case 'i':
+ dontExecute = 1;
+ break;
+
+ case 'K':
#ifdef LOCK_MGR_DEBUG
- lockDebug = atoi(optarg);
+ lockDebug = atoi(optarg);
#else
- fprintf(stderr, "Lock debug not compiled in\n");
+ fprintf(stderr, "Lock debug not compiled in\n");
#endif
- break;
-
- case 'L':
- /* --------------------
- * turn off locking
- * --------------------
- */
- lockingOff = 1;
- break;
-
- case 'm':
- /* start up a listening backend that can respond to
- multiple front-ends. (Note: all the front-end connections
- are still connected to a single-threaded backend. Requests
- are FCFS. Everything is in one transaction
- */
- multiplexedBackend = true;
- serverPortnum = atoi(optarg);
- break;
- case 'M':
- exit(PostmasterMain(argc, argv));
- break;
- case 'N':
- /* ----------------
- * N - Don't use newline as a query delimiter
- * ----------------
- */
- UseNewLine = 0;
- break;
-
- case 'o':
- /* ----------------
- * o - send output (stdout and stderr) to the given file
- * ----------------
- */
- strNcpy(OutputFileName, optarg, MAXPGPATH);
- break;
-
- case 'p': /* started by postmaster */
- /* ----------------
- * p - special flag passed if backend was forked
- * by a postmaster.
- * ----------------
- */
- IsUnderPostmaster = true;
- break;
-
- case 'P':
- /* ----------------
- * P - Use the passed file descriptor number as the port
- * on which to communicate with the user. This is ONLY
- * useful for debugging when fired up by the postmaster.
- * ----------------
- */
- Portfd = atoi(optarg);
- break;
-
- case 'Q':
- /* ----------------
- * Q - set Quiet mode (reduce debugging output)
- * ----------------
- */
- flagQ = 1;
- break;
-
- case 'S':
- /* ----------------
- * S - amount of sort memory to use in 1k bytes
- * ----------------
- */
- SortMem = atoi(optarg);
- break;
-
- case 's':
- /* ----------------
- * s - report usage statistics (timings) after each query
- * ----------------
- */
- ShowStats = 1;
- StatFp = stderr;
- break;
-
- case 't':
- /* ----------------
- * tell postgres to report usage statistics (timings) for
- * each query
- *
- * -tpa[rser] = print stats for parser time of each query
- * -tpl[anner] = print stats for planner time of each query
- * -te[xecutor] = print stats for executor time of each query
- * caution: -s can not be used together with -t.
- * ----------------
- */
- StatFp = stderr;
- switch (optarg[0]) {
- case 'p': if (optarg[1] == 'a')
- ShowParserStats = 1;
- else if (optarg[1] == 'l')
- ShowPlannerStats = 1;
- else
- errs++;
- break;
- case 'e': ShowExecutorStats = 1; break;
- default: errs++; break;
- }
- break;
-
- case 'x':
-#if 0 /* planner/xfunc.h */
- /* control joey hellerstein's expensive function optimization */
- if (XfuncMode != 0)
- {
- fprintf(stderr, "only one -x flag is allowed\n");
- errs++;
- break;
- }
- if (strcmp(optarg, "off") == 0)
- XfuncMode = XFUNC_OFF;
- else if (strcmp(optarg, "nor") == 0)
- XfuncMode = XFUNC_NOR;
- else if (strcmp(optarg, "nopull") == 0)
- XfuncMode = XFUNC_NOPULL;
- else if (strcmp(optarg, "nopm") == 0)
- XfuncMode = XFUNC_NOPM;
- else if (strcmp(optarg, "pullall") == 0)
- XfuncMode = XFUNC_PULLALL;
- else if (strcmp(optarg, "wait") == 0)
- XfuncMode = XFUNC_WAIT;
- else {
- fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
- errs++;
- }
+ break;
+
+ case 'L':
+ /* --------------------
+ * turn off locking
+ * --------------------
+ */
+ lockingOff = 1;
+ break;
+
+ case 'm':
+
+ /*
+ * start up a listening backend that can respond to multiple
+ * front-ends. (Note: all the front-end connections are
+ * still connected to a single-threaded backend. Requests are
+ * FCFS. Everything is in one transaction
+ */
+ multiplexedBackend = true;
+ serverPortnum = atoi(optarg);
+ break;
+ case 'M':
+ exit(PostmasterMain(argc, argv));
+ break;
+ case 'N':
+ /* ----------------
+ * N - Don't use newline as a query delimiter
+ * ----------------
+ */
+ UseNewLine = 0;
+ break;
+
+ case 'o':
+ /* ----------------
+ * o - send output (stdout and stderr) to the given file
+ * ----------------
+ */
+ strNcpy(OutputFileName, optarg, MAXPGPATH);
+ break;
+
+ case 'p': /* started by postmaster */
+ /* ----------------
+ * p - special flag passed if backend was forked
+ * by a postmaster.
+ * ----------------
+ */
+ IsUnderPostmaster = true;
+ break;
+
+ case 'P':
+ /* ----------------
+ * P - Use the passed file descriptor number as the port
+ * on which to communicate with the user. This is ONLY
+ * useful for debugging when fired up by the postmaster.
+ * ----------------
+ */
+ Portfd = atoi(optarg);
+ break;
+
+ case 'Q':
+ /* ----------------
+ * Q - set Quiet mode (reduce debugging output)
+ * ----------------
+ */
+ flagQ = 1;
+ break;
+
+ case 'S':
+ /* ----------------
+ * S - amount of sort memory to use in 1k bytes
+ * ----------------
+ */
+ SortMem = atoi(optarg);
+ break;
+
+ case 's':
+ /* ----------------
+ * s - report usage statistics (timings) after each query
+ * ----------------
+ */
+ ShowStats = 1;
+ StatFp = stderr;
+ break;
+
+ case 't':
+ /* ----------------
+ * tell postgres to report usage statistics (timings) for
+ * each query
+ *
+ * -tpa[rser] = print stats for parser time of each query
+ * -tpl[anner] = print stats for planner time of each query
+ * -te[xecutor] = print stats for executor time of each query
+ * caution: -s can not be used together with -t.
+ * ----------------
+ */
+ StatFp = stderr;
+ switch (optarg[0])
+ {
+ case 'p':
+ if (optarg[1] == 'a')
+ ShowParserStats = 1;
+ else if (optarg[1] == 'l')
+ ShowPlannerStats = 1;
+ else
+ errs++;
+ break;
+ case 'e':
+ ShowExecutorStats = 1;
+ break;
+ default:
+ errs++;
+ break;
+ }
+ break;
+
+ case 'x':
+#if 0 /* planner/xfunc.h */
+ /* control joey hellerstein's expensive function optimization */
+ if (XfuncMode != 0)
+ {
+ fprintf(stderr, "only one -x flag is allowed\n");
+ errs++;
+ break;
+ }
+ if (strcmp(optarg, "off") == 0)
+ XfuncMode = XFUNC_OFF;
+ else if (strcmp(optarg, "nor") == 0)
+ XfuncMode = XFUNC_NOR;
+ else if (strcmp(optarg, "nopull") == 0)
+ XfuncMode = XFUNC_NOPULL;
+ else if (strcmp(optarg, "nopm") == 0)
+ XfuncMode = XFUNC_NOPM;
+ else if (strcmp(optarg, "pullall") == 0)
+ XfuncMode = XFUNC_PULLALL;
+ else if (strcmp(optarg, "wait") == 0)
+ XfuncMode = XFUNC_WAIT;
+ else
+ {
+ fprintf(stderr, "use -x {off,nor,nopull,nopm,pullall,wait}\n");
+ errs++;
+ }
#endif
- break;
-
- default:
- /* ----------------
- * default: bad command line option
- * ----------------
- */
- errs++;
- }
-
- /* ----------------
- * get user name and pathname and check command line validity
- * ----------------
- */
- SetPgUserName();
- userName = GetPgUserName();
-
- if (FindBackend(pg_pathname, argv[0]) < 0)
- elog(FATAL, "%s: could not locate executable, bailing out...",
- argv[0]);
-
- if (errs || argc - optind > 1) {
- usage (argv[0]);
- exitpg(1);
- } else if (argc - optind == 1) {
- DBName = argv[optind];
- } else if ((DBName = userName) == NULL) {
- fprintf(stderr, "%s: USER undefined and no database specified\n",
- argv[0]);
- exitpg(1);
- }
-
- if (ShowStats &&
- (ShowParserStats || ShowPlannerStats || ShowExecutorStats)) {
- fprintf(stderr, "-s can not be used together with -t.\n");
- exitpg(1);
- }
-
- if (!DataDir) {
- fprintf(stderr, "%s does not know where to find the database system "
- "data. You must specify the directory that contains the "
- "database system either by specifying the -D invocation "
- "option or by setting the PGDATA environment variable.\n\n",
- argv[0]);
- exitpg(1);
- }
-
- Noversion = flagC;
- Quiet = flagQ;
- EchoQuery = flagE;
- EuroDates = flagEu;
-
- /* ----------------
- * print flags
- * ----------------
- */
- if (! Quiet) {
- puts("\t---debug info---");
- printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
- printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
- printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
- printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
- printf("\tbufsize = %d\n", NBuffers);
- printf("\tsortmem = %d\n", SortMem);
-
- printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
- printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
- printf("\tDatabaseName = [%s]\n", DBName);
- puts("\t----------------\n");
- }
-
- /* ----------------
- * initialize portal file descriptors
- * ----------------
- */
- if (IsUnderPostmaster == true) {
- if (Portfd < 0) {
- fprintf(stderr,
- "Postmaster flag set: no port number specified, use /dev/null\n");
- Portfd = open(NULL_DEV, O_RDWR, 0666);
- }
- pq_init(Portfd);
- }
-
- if (multiplexedBackend) {
- if (serverPortnum == 0 ||
- StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
- {
- fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
- exit(1);
- }
+ break;
+
+ default:
+ /* ----------------
+ * default: bad command line option
+ * ----------------
+ */
+ errs++;
+ }
+
+ /* ----------------
+ * get user name and pathname and check command line validity
+ * ----------------
+ */
+ SetPgUserName();
+ userName = GetPgUserName();
+
+ if (FindBackend(pg_pathname, argv[0]) < 0)
+ elog(FATAL, "%s: could not locate executable, bailing out...",
+ argv[0]);
+
+ if (errs || argc - optind > 1)
+ {
+ usage(argv[0]);
+ exitpg(1);
+ }
+ else if (argc - optind == 1)
+ {
+ DBName = argv[optind];
+ }
+ else if ((DBName = userName) == NULL)
+ {
+ fprintf(stderr, "%s: USER undefined and no database specified\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ if (ShowStats &&
+ (ShowParserStats || ShowPlannerStats || ShowExecutorStats))
+ {
+ fprintf(stderr, "-s can not be used together with -t.\n");
+ exitpg(1);
+ }
+
+ if (!DataDir)
+ {
+ fprintf(stderr, "%s does not know where to find the database system "
+ "data. You must specify the directory that contains the "
+ "database system either by specifying the -D invocation "
+ "option or by setting the PGDATA environment variable.\n\n",
+ argv[0]);
+ exitpg(1);
+ }
+
+ Noversion = flagC;
+ Quiet = flagQ;
+ EchoQuery = flagE;
+ EuroDates = flagEu;
+
+ /* ----------------
+ * print flags
+ * ----------------
+ */
+ if (!Quiet)
+ {
+ puts("\t---debug info---");
+ printf("\tQuiet = %c\n", Quiet ? 't' : 'f');
+ printf("\tNoversion = %c\n", Noversion ? 't' : 'f');
+ printf("\ttimings = %c\n", ShowStats ? 't' : 'f');
+ printf("\tdates = %s\n", EuroDates ? "European" : "Normal");
+ printf("\tbufsize = %d\n", NBuffers);
+ printf("\tsortmem = %d\n", SortMem);
+
+ printf("\tquery echo = %c\n", EchoQuery ? 't' : 'f');
+ printf("\tmultiplexed backend? = %c\n", multiplexedBackend ? 't' : 'f');
+ printf("\tDatabaseName = [%s]\n", DBName);
+ puts("\t----------------\n");
+ }
+
+ /* ----------------
+ * initialize portal file descriptors
+ * ----------------
+ */
+ if (IsUnderPostmaster == true)
+ {
+ if (Portfd < 0)
+ {
+ fprintf(stderr,
+ "Postmaster flag set: no port number specified, use /dev/null\n");
+ Portfd = open(NULL_DEV, O_RDWR, 0666);
+ }
+ pq_init(Portfd);
+ }
+
+ if (multiplexedBackend)
+ {
+ if (serverPortnum == 0 ||
+ StreamServerPort(hostName, serverPortnum, &serverSock) != STATUS_OK)
+ {
+ fprintf(stderr, "Postgres: cannot create stream port %d\n", serverPortnum);
+ exit(1);
+ }
/*
{
- char buf[100];
- sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
- puts(buf);
+ char buf[100];
+ sprintf(buf, "stream port %d created, socket = %d\n", serverPortnum, serverSock);
+ puts(buf);
}
*/
- FD_ZERO(&rmask);
- FD_ZERO(&basemask);
- FD_SET(serverSock, &basemask);
-
- frontendList = DLNewList();
- /* add the original FrontEnd to the list */
- if (IsUnderPostmaster == true) {
- FrontEnd *fe = malloc(sizeof(FrontEnd));
-
- FD_SET(Portfd, &basemask);
- maxFd = Max(serverSock,Portfd) + 1;
-
- fe->fn_connected = true;
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- fe->fn_done = false;
- (fe->fn_port).sock = Portfd;
- DLAddHead(frontendList, DLNewElem(fe));
- numFE++;
- } else {
- numFE = 1;
- maxFd = serverSock + 1;
- }
- }
-
- if (IsUnderPostmaster || multiplexedBackend)
- whereToSendOutput = Remote;
- else
- whereToSendOutput = Debug;
-
- SetProcessingMode(InitProcessing);
-
- /* initialize */
- if (! Quiet) {
- puts("\tInitPostgres()..");
- }
-
- InitPostgres(DBName);
-
- /* ----------------
- * if an exception is encountered, processing resumes here
- * so we abort the current transaction and start a new one.
- * This must be done after we initialize the slave backends
- * so that the slaves signal the master to abort the transaction
- * rather than calling AbortCurrentTransaction() themselves.
- *
- * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
- * us back here.
- * ----------------
- */
-
- pqsignal(SIGHUP, handle_warn);
-
- if (sigsetjmp(Warn_restart, 1) != 0) {
- InWarn = 1;
-
- time(&tim);
-
- if (! Quiet)
- printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
-
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- AbortCurrentTransaction();
- }
- InWarn = 0;
-
- /* ----------------
- * POSTGRES main processing loop begins here
- * ----------------
- */
- if (IsUnderPostmaster == false) {
- puts("\nPOSTGRES backend interactive interface");
- puts("$Revision: 1.42 $ $Date: 1997/08/19 21:34:04 $");
- }
-
- /* ----------------
- * if stable main memory is assumed (-S(old) flag is set), it is necessary
- * to flush all dirty shared buffers before exit
- * plai 8/7/90
- * ----------------
- */
- if (!TransactionFlushEnabled())
- on_exitpg(FlushBufferPool, (caddr_t) 0);
-
- for (;;) {
-
- if (multiplexedBackend) {
- if (numFE == 0)
- break;
-
- memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
- nSelected = select(maxFd, &rmask,0,0,0);
-
- if (nSelected < 0) {
-
- if (errno == EINTR) continue;
- fprintf(stderr,"postgres: multiplexed backend select failed\n");
- exitpg(1);
- }
- if (FD_ISSET(serverSock, &rmask)) {
- /* new connection pending on our well-known port's socket */
- newFE = (FrontEnd*) malloc (sizeof(FrontEnd));
- memset(newFE, 0, sizeof(FrontEnd));
- newFE->fn_connected = false;
- newFE->fn_done = false;
- newPort = &(newFE->fn_port);
- if (StreamConnection(serverSock,newPort) != STATUS_OK) {
- StreamClose(newPort->sock);
- newFd = -1;
- }
- else {
- DLAddHead(frontendList, DLNewElem(newFE));
- numFE++;
- newFd = newPort->sock;
- if (newFd >= maxFd) maxFd = newFd + 1;
- FD_SET(newFd, &rmask);
- FD_SET(newFd, &basemask);
- --nSelected;
- FD_CLR(serverSock, &rmask);
- }
- continue;
- } /* if FD_ISSET(serverSock) */
-
- /* if we get here, it means that the serverSocket was not the one
- selected. Instead, one of the front ends was selected.
- find which one */
- curr = DLGetHead(frontendList);
- while (curr) {
- FrontEnd *fe = (FrontEnd*)DLE_VAL(curr);
- Port *port = &(fe->fn_port);
-
- /* this is lifted from postmaster.c */
- if (FD_ISSET(port->sock, &rmask)) {
- if (fe->fn_connected == false) {
- /* we have a message from a new frontEnd */
- status = PacketReceive(port, &port->buf, NON_BLOCKING);
- if (status == STATUS_OK) {
- fe->fn_connected = true;
- pq_init(port->sock);
- fe->fn_Pfin = Pfin;
- fe->fn_Pfout = Pfout;
- }
- else
- fprintf(stderr,"Multiplexed backend: error in reading packets from %d\n", port->sock);
- }
- else /* we have a query from an existing, active FrontEnd */
- {
- Pfin = fe->fn_Pfin;
- Pfout = fe->fn_Pfout;
- currentFE = fe;
- }
- if (fe->fn_done)
- {
- Dlelem *c = curr;
- curr = DLGetSucc(curr);
- DLRemove(c);
- }
- break;
- }
- else
- curr = DLGetSucc(curr);
- }
- }
- /* ----------------
- * (1) read a command.
- * ----------------
- */
- memset(parser_input, 0, MAX_PARSE_BUFFER);
-
- firstchar = ReadCommand(parser_input, multiplexedBackend);
- /* process the command */
- switch (firstchar) {
- /* ----------------
- * 'F' indicates a fastpath call.
- * XXX HandleFunctionRequest
- * ----------------
- */
- case 'F':
- IsEmptyQuery = false;
-
- /* start an xact for this function invocation */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
-
- StartTransactionCommand();
- HandleFunctionRequest();
- break;
-
- /* ----------------
- * 'Q' indicates a user query
- * ----------------
- */
- case 'Q':
- fflush(stdout);
-
- if ( strspn(parser_input," \t\n") == strlen(parser_input)) {
- /* ----------------
- * if there is nothing in the input buffer, don't bother
- * trying to parse and execute anything..
- * ----------------
- */
- IsEmptyQuery = true;
- } else {
- /* ----------------
- * otherwise, process the input string.
- * ----------------
- */
- IsEmptyQuery = false;
- if (ShowStats)
- ResetUsage();
-
- /* start an xact for this query */
- if (! Quiet) {
- time(&tim);
- printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
- }
- StartTransactionCommand();
-
- pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
-
- if (ShowStats)
- ShowUsage();
- }
- break;
-
- /* ----------------
- * 'X' means that the frontend is closing down the socket
- * ----------------
- */
- case 'X':
- IsEmptyQuery = true;
- if (multiplexedBackend) {
- FD_CLR(currentFE->fn_port.sock, &basemask);
- currentFE->fn_done = true;
- numFE--;
- }
- pq_close();
- break;
-
- default:
- elog(WARN,"unknown frontend message was recieved");
- }
-
- /* ----------------
- * (3) commit the current transaction
- *
- * Note: if we had an empty input buffer, then we didn't
- * call pg_eval, so we don't bother to commit this transaction.
- * ----------------
- */
- if (! IsEmptyQuery) {
- if (! Quiet) {
- time(&tim);
- printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
- }
- CommitTransactionCommand();
-
- } else {
- if (IsUnderPostmaster || multiplexedBackend)
- NullCommand(Remote);
- }
-
-} /* infinite for-loop */
- exitpg(0);
- return 1;
+ FD_ZERO(&rmask);
+ FD_ZERO(&basemask);
+ FD_SET(serverSock, &basemask);
+
+ frontendList = DLNewList();
+ /* add the original FrontEnd to the list */
+ if (IsUnderPostmaster == true)
+ {
+ FrontEnd *fe = malloc(sizeof(FrontEnd));
+
+ FD_SET(Portfd, &basemask);
+ maxFd = Max(serverSock, Portfd) + 1;
+
+ fe->fn_connected = true;
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ fe->fn_done = false;
+ (fe->fn_port).sock = Portfd;
+ DLAddHead(frontendList, DLNewElem(fe));
+ numFE++;
+ }
+ else
+ {
+ numFE = 1;
+ maxFd = serverSock + 1;
+ }
+ }
+
+ if (IsUnderPostmaster || multiplexedBackend)
+ whereToSendOutput = Remote;
+ else
+ whereToSendOutput = Debug;
+
+ SetProcessingMode(InitProcessing);
+
+ /* initialize */
+ if (!Quiet)
+ {
+ puts("\tInitPostgres()..");
+ }
+
+ InitPostgres(DBName);
+
+ /* ----------------
+ * if an exception is encountered, processing resumes here
+ * so we abort the current transaction and start a new one.
+ * This must be done after we initialize the slave backends
+ * so that the slaves signal the master to abort the transaction
+ * rather than calling AbortCurrentTransaction() themselves.
+ *
+ * Note: elog(WARN) causes a kill(getpid(),1) to occur sending
+ * us back here.
+ * ----------------
+ */
+
+ pqsignal(SIGHUP, handle_warn);
+
+ if (sigsetjmp(Warn_restart, 1) != 0)
+ {
+ InWarn = 1;
+
+ time(&tim);
+
+ if (!Quiet)
+ printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
+
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ AbortCurrentTransaction();
+ }
+ InWarn = 0;
+
+ /* ----------------
+ * POSTGRES main processing loop begins here
+ * ----------------
+ */
+ if (IsUnderPostmaster == false)
+ {
+ puts("\nPOSTGRES backend interactive interface");
+ puts("$Revision: 1.43 $ $Date: 1997/09/07 04:49:33 $");
+ }
+
+ /* ----------------
+ * if stable main memory is assumed (-S(old) flag is set), it is necessary
+ * to flush all dirty shared buffers before exit
+ * plai 8/7/90
+ * ----------------
+ */
+ if (!TransactionFlushEnabled())
+ on_exitpg(FlushBufferPool, (caddr_t) 0);
+
+ for (;;)
+ {
+
+ if (multiplexedBackend)
+ {
+ if (numFE == 0)
+ break;
+
+ memmove((char *) &rmask, (char *) &basemask, sizeof(fd_set));
+ nSelected = select(maxFd, &rmask, 0, 0, 0);
+
+ if (nSelected < 0)
+ {
+
+ if (errno == EINTR)
+ continue;
+ fprintf(stderr, "postgres: multiplexed backend select failed\n");
+ exitpg(1);
+ }
+ if (FD_ISSET(serverSock, &rmask))
+ {
+ /* new connection pending on our well-known port's socket */
+ newFE = (FrontEnd *) malloc(sizeof(FrontEnd));
+ memset(newFE, 0, sizeof(FrontEnd));
+ newFE->fn_connected = false;
+ newFE->fn_done = false;
+ newPort = &(newFE->fn_port);
+ if (StreamConnection(serverSock, newPort) != STATUS_OK)
+ {
+ StreamClose(newPort->sock);
+ newFd = -1;
+ }
+ else
+ {
+ DLAddHead(frontendList, DLNewElem(newFE));
+ numFE++;
+ newFd = newPort->sock;
+ if (newFd >= maxFd)
+ maxFd = newFd + 1;
+ FD_SET(newFd, &rmask);
+ FD_SET(newFd, &basemask);
+ --nSelected;
+ FD_CLR(serverSock, &rmask);
+ }
+ continue;
+ } /* if FD_ISSET(serverSock) */
+
+ /*
+ * if we get here, it means that the serverSocket was not the
+ * one selected. Instead, one of the front ends was selected.
+ * find which one
+ */
+ curr = DLGetHead(frontendList);
+ while (curr)
+ {
+ FrontEnd *fe = (FrontEnd *) DLE_VAL(curr);
+ Port *port = &(fe->fn_port);
+
+ /* this is lifted from postmaster.c */
+ if (FD_ISSET(port->sock, &rmask))
+ {
+ if (fe->fn_connected == false)
+ {
+ /* we have a message from a new frontEnd */
+ status = PacketReceive(port, &port->buf, NON_BLOCKING);
+ if (status == STATUS_OK)
+ {
+ fe->fn_connected = true;
+ pq_init(port->sock);
+ fe->fn_Pfin = Pfin;
+ fe->fn_Pfout = Pfout;
+ }
+ else
+ fprintf(stderr, "Multiplexed backend: error in reading packets from %d\n", port->sock);
+ }
+ else
+/* we have a query from an existing, active FrontEnd */
+ {
+ Pfin = fe->fn_Pfin;
+ Pfout = fe->fn_Pfout;
+ currentFE = fe;
+ }
+ if (fe->fn_done)
+ {
+ Dlelem *c = curr;
+
+ curr = DLGetSucc(curr);
+ DLRemove(c);
+ }
+ break;
+ }
+ else
+ curr = DLGetSucc(curr);
+ }
+ }
+ /* ----------------
+ * (1) read a command.
+ * ----------------
+ */
+ memset(parser_input, 0, MAX_PARSE_BUFFER);
+
+ firstchar = ReadCommand(parser_input, multiplexedBackend);
+ /* process the command */
+ switch (firstchar)
+ {
+ /* ----------------
+ * 'F' indicates a fastpath call.
+ * XXX HandleFunctionRequest
+ * ----------------
+ */
+ case 'F':
+ IsEmptyQuery = false;
+
+ /* start an xact for this function invocation */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+
+ StartTransactionCommand();
+ HandleFunctionRequest();
+ break;
+
+ /* ----------------
+ * 'Q' indicates a user query
+ * ----------------
+ */
+ case 'Q':
+ fflush(stdout);
+
+ if (strspn(parser_input, " \t\n") == strlen(parser_input))
+ {
+ /* ----------------
+ * if there is nothing in the input buffer, don't bother
+ * trying to parse and execute anything..
+ * ----------------
+ */
+ IsEmptyQuery = true;
+ }
+ else
+ {
+ /* ----------------
+ * otherwise, process the input string.
+ * ----------------
+ */
+ IsEmptyQuery = false;
+ if (ShowStats)
+ ResetUsage();
+
+ /* start an xact for this query */
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tStartTransactionCommand() at %s\n", ctime(&tim));
+ }
+ StartTransactionCommand();
+
+ pg_eval(parser_input, (char **) NULL, (Oid *) NULL, 0);
+
+ if (ShowStats)
+ ShowUsage();
+ }
+ break;
+
+ /* ----------------
+ * 'X' means that the frontend is closing down the socket
+ * ----------------
+ */
+ case 'X':
+ IsEmptyQuery = true;
+ if (multiplexedBackend)
+ {
+ FD_CLR(currentFE->fn_port.sock, &basemask);
+ currentFE->fn_done = true;
+ numFE--;
+ }
+ pq_close();
+ break;
+
+ default:
+ elog(WARN, "unknown frontend message was recieved");
+ }
+
+ /* ----------------
+ * (3) commit the current transaction
+ *
+ * Note: if we had an empty input buffer, then we didn't
+ * call pg_eval, so we don't bother to commit this transaction.
+ * ----------------
+ */
+ if (!IsEmptyQuery)
+ {
+ if (!Quiet)
+ {
+ time(&tim);
+ printf("\tCommitTransactionCommand() at %s\n", ctime(&tim));
+ }
+ CommitTransactionCommand();
+
+ }
+ else
+ {
+ if (IsUnderPostmaster || multiplexedBackend)
+ NullCommand(Remote);
+ }
+
+ } /* infinite for-loop */
+ exitpg(0);
+ return 1;
}
#ifndef HAVE_GETRUSAGE
#include "rusagestub.h"
-#else /* HAVE_GETRUSAGE */
+#else /* HAVE_GETRUSAGE */
#include <sys/resource.h>
-#endif /* HAVE_GETRUSAGE */
+#endif /* HAVE_GETRUSAGE */
-struct rusage Save_r;
-struct timeval Save_t;
+struct rusage Save_r;
+struct timeval Save_t;
void
ResetUsage(void)
{
- struct timezone tz;
- getrusage(RUSAGE_SELF, &Save_r);
- gettimeofday(&Save_t, &tz);
- ResetBufferUsage();
-/* ResetTupleCount(); */
+ struct timezone tz;
+
+ getrusage(RUSAGE_SELF, &Save_r);
+ gettimeofday(&Save_t, &tz);
+ ResetBufferUsage();
+/* ResetTupleCount(); */
}
void
ShowUsage(void)
{
- struct timeval user, sys;
- struct timeval elapse_t;
- struct timezone tz;
- struct rusage r;
-
- getrusage(RUSAGE_SELF, &r);
- gettimeofday(&elapse_t, &tz);
- memmove((char *)&user, (char *)&r.ru_utime, sizeof(user));
- memmove((char *)&sys, (char *)&r.ru_stime,sizeof(sys));
- if (elapse_t.tv_usec < Save_t.tv_usec) {
- elapse_t.tv_sec--;
- elapse_t.tv_usec += 1000000;
- }
- if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) {
- r.ru_utime.tv_sec--;
- r.ru_utime.tv_usec += 1000000;
- }
- if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec) {
- r.ru_stime.tv_sec--;
- r.ru_stime.tv_usec += 1000000;
- }
-
- /*
- * the only stats we don't show here are for memory usage -- i can't
- * figure out how to interpret the relevant fields in the rusage
- * struct, and they change names across o/s platforms, anyway.
- * if you can figure out what the entries mean, you can somehow
- * extract resident set size, shared text size, and unshared data
- * and stack sizes.
- */
-
- fprintf(StatFp, "! system usage stats:\n");
- fprintf(StatFp,
- "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
- (long int) elapse_t.tv_sec - Save_t.tv_sec,
- (long int) elapse_t.tv_usec - Save_t.tv_usec,
- (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
- (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
- (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
- (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
- fprintf(StatFp,
- "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
- (long int) user.tv_sec,
- (long int) user.tv_usec,
- (long int) sys.tv_sec,
- (long int) sys.tv_usec);
+ struct timeval user,
+ sys;
+ struct timeval elapse_t;
+ struct timezone tz;
+ struct rusage r;
+
+ getrusage(RUSAGE_SELF, &r);
+ gettimeofday(&elapse_t, &tz);
+ memmove((char *) &user, (char *) &r.ru_utime, sizeof(user));
+ memmove((char *) &sys, (char *) &r.ru_stime, sizeof(sys));
+ if (elapse_t.tv_usec < Save_t.tv_usec)
+ {
+ elapse_t.tv_sec--;
+ elapse_t.tv_usec += 1000000;
+ }
+ if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec)
+ {
+ r.ru_utime.tv_sec--;
+ r.ru_utime.tv_usec += 1000000;
+ }
+ if (r.ru_stime.tv_usec < Save_r.ru_stime.tv_usec)
+ {
+ r.ru_stime.tv_sec--;
+ r.ru_stime.tv_usec += 1000000;
+ }
+
+ /*
+ * the only stats we don't show here are for memory usage -- i can't
+ * figure out how to interpret the relevant fields in the rusage
+ * struct, and they change names across o/s platforms, anyway. if you
+ * can figure out what the entries mean, you can somehow extract
+ * resident set size, shared text size, and unshared data and stack
+ * sizes.
+ */
+
+ fprintf(StatFp, "! system usage stats:\n");
+ fprintf(StatFp,
+ "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
+ (long int) elapse_t.tv_sec - Save_t.tv_sec,
+ (long int) elapse_t.tv_usec - Save_t.tv_usec,
+ (long int) r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec,
+ (long int) r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec,
+ (long int) r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec,
+ (long int) r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec);
+ fprintf(StatFp,
+ "!\t[%ld.%06ld user %ld.%06ld sys total]\n",
+ (long int) user.tv_sec,
+ (long int) user.tv_usec,
+ (long int) sys.tv_sec,
+ (long int) sys.tv_usec);
#ifdef HAVE_GETRUSAGE
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
- r.ru_inblock - Save_r.ru_inblock,
- /* they only drink coffee at dec */
- r.ru_oublock - Save_r.ru_oublock,
- r.ru_inblock, r.ru_oublock);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
- r.ru_majflt - Save_r.ru_majflt,
- r.ru_minflt - Save_r.ru_minflt,
- r.ru_majflt, r.ru_minflt,
- r.ru_nswap - Save_r.ru_nswap,
- r.ru_nswap);
- fprintf(StatFp,
- "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
- r.ru_nsignals - Save_r.ru_nsignals,
- r.ru_nsignals,
- r.ru_msgrcv - Save_r.ru_msgrcv,
- r.ru_msgsnd - Save_r.ru_msgsnd,
- r.ru_msgrcv, r.ru_msgsnd);
- fprintf(StatFp,
- "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
- r.ru_nvcsw - Save_r.ru_nvcsw,
- r.ru_nivcsw - Save_r.ru_nivcsw,
- r.ru_nvcsw, r.ru_nivcsw);
-#endif /* HAVE_GETRUSAGE */
- fprintf(StatFp, "! postgres usage stats:\n");
- PrintBufferUsage(StatFp);
-/* DisplayTupleCount(StatFp); */
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
+ r.ru_inblock - Save_r.ru_inblock,
+ /* they only drink coffee at dec */
+ r.ru_oublock - Save_r.ru_oublock,
+ r.ru_inblock, r.ru_oublock);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
+ r.ru_majflt - Save_r.ru_majflt,
+ r.ru_minflt - Save_r.ru_minflt,
+ r.ru_majflt, r.ru_minflt,
+ r.ru_nswap - Save_r.ru_nswap,
+ r.ru_nswap);
+ fprintf(StatFp,
+ "!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
+ r.ru_nsignals - Save_r.ru_nsignals,
+ r.ru_nsignals,
+ r.ru_msgrcv - Save_r.ru_msgrcv,
+ r.ru_msgsnd - Save_r.ru_msgsnd,
+ r.ru_msgrcv, r.ru_msgsnd);
+ fprintf(StatFp,
+ "!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
+ r.ru_nvcsw - Save_r.ru_nvcsw,
+ r.ru_nivcsw - Save_r.ru_nivcsw,
+ r.ru_nvcsw, r.ru_nivcsw);
+#endif /* HAVE_GETRUSAGE */
+ fprintf(StatFp, "! postgres usage stats:\n");
+ PrintBufferUsage(StatFp);
+/* DisplayTupleCount(StatFp); */
}