diff options
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 2789 |
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); */ } |