postgres/src/backend/tcop/postgres.c

2549 lines
61 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* postgres.c
* POSTGRES C Backend Interface
*
2002-06-20 20:29:54 +00:00
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.308 2002/11/14 23:53:27 momjian Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
* hence the main module of the "traffic cop".
*
*-------------------------------------------------------------------------
*/
1996-11-08 06:02:30 +00:00
#include "postgres.h"
1996-11-08 06:02:30 +00:00
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
1996-11-08 06:02:30 +00:00
#include <fcntl.h>
#include <sys/socket.h>
#include <errno.h>
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_GETOPT_H
1999-07-16 05:23:30 +00:00
#include <getopt.h>
1999-01-17 06:20:06 +00:00
#endif
#include "access/xlog.h"
#include "commands/async.h"
#include "commands/trigger.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
#include "libpq/pqsignal.h"
1999-07-16 05:00:38 +00:00
#include "miscadmin.h"
#include "nodes/print.h"
#include "optimizer/cost.h"
#include "optimizer/planner.h"
#include "parser/analyze.h"
#include "parser/parse.h"
#include "parser/parser.h"
1999-07-16 03:14:30 +00:00
#include "rewrite/rewriteHandler.h"
#include "storage/ipc.h"
#include "storage/proc.h"
#include "tcop/fastpath.h"
#include "tcop/pquery.h"
1999-07-16 03:14:30 +00:00
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/guc.h"
#include "utils/memutils.h"
#include "utils/ps_status.h"
1999-07-16 05:00:38 +00:00
#include "mb/pg_wchar.h"
#include "pgstat.h"
/* ----------------
* global variables
* ----------------
*/
2001-03-22 04:01:46 +00:00
extern int optind;
extern char *optarg;
2002-09-04 20:31:48 +00:00
char *debug_query_string; /* for pgmonitor and
* log_min_error_statement */
/* Note: whereToSendOutput is initialized for the bootstrap/standalone case */
CommandDest whereToSendOutput = Debug;
2001-03-22 04:01:46 +00:00
static bool dontExecute = false;
/* note: these declarations had better match tcopprot.h */
sigjmp_buf Warn_restart;
bool Warn_restart_ready = false;
bool InError = false;
static bool EchoQuery = false; /* default don't echo */
/*
* Flag to mark SIGHUP. Whenever the main loop comes around it
* will reread the configuration file. (Better than doing the
* reading in the signal handler, ey?)
*/
static volatile bool got_SIGHUP = false;
/* ----------------
* 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) */
#else
int UseNewLine = 0; /* Use EOF as query delimiters */
#endif /* TCOP_DONTUSENEWLINE */
/*
** Flags for expensive function optimization -- JMH 3/9/92
*/
int XfuncMode = 0;
/* ----------------------------------------------------------------
* decls for routines only used in this file
* ----------------------------------------------------------------
*/
static int InteractiveBackend(StringInfo inBuf);
static int SocketBackend(StringInfo inBuf);
static int ReadCommand(StringInfo inBuf);
static void start_xact_command(void);
static void finish_xact_command(bool forceCommit);
static void SigHupHandler(SIGNAL_ARGS);
static void FloatExceptionHandler(SIGNAL_ARGS);
static const char *CreateCommandTag(Node *parsetree);
/* ----------------------------------------------------------------
* routines to obtain user input
* ----------------------------------------------------------------
*/
/* ----------------
* InteractiveBackend() is called for user interactive connections
* the string entered by the user is placed in its parameter inBuf.
*
* EOF is returned if end-of-file input is seen; time to shut down.
* ----------------
*/
static int
InteractiveBackend(StringInfo inBuf)
{
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("backend> ");
fflush(stdout);
/* Reset inBuf to empty */
inBuf->len = 0;
inBuf->data[0] = '\0';
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)
{
/* discard backslash from inBuf */
inBuf->data[--inBuf->len] = '\0';
backslashSeen = false;
continue;
}
else
{
/* keep the newline character */
appendStringInfoChar(inBuf, '\n');
break;
}
}
else if (c == '\\')
backslashSeen = true;
else
backslashSeen = false;
appendStringInfoChar(inBuf, (char) c);
}
if (c == EOF)
end = true;
}
else
{
/*
* otherwise read characters until EOF.
*/
while ((c = getc(stdin)) != EOF)
appendStringInfoChar(inBuf, (char) c);
if (inBuf->len == 0)
end = true;
}
if (end)
return EOF;
/*
* otherwise we have a user query so process it.
*/
break;
}
/*
* if the query echo flag was given, print the query..
*/
if (EchoQuery)
printf("statement: %s\n", inBuf->data);
fflush(stdout);
1998-09-01 03:29:17 +00:00
return 'Q';
}
/* ----------------
* 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 fastpath function call (case 'F') then
* the function call is processed in HandleFunctionRequest()
* (now called from PostgresMain()).
*
* EOF is returned if the connection is lost.
* ----------------
*/
static int
SocketBackend(StringInfo inBuf)
{
int qtype;
/*
* get input from the frontend
*/
qtype = pq_getbyte();
switch (qtype)
{
case EOF:
/* frontend disconnected */
break;
/*
* 'Q': user entered a query
*/
case 'Q':
if (pq_getstr(inBuf))
return EOF;
break;
/*
* 'F': calling user/system functions
*/
case 'F':
if (pq_getstr(inBuf))
return EOF; /* ignore "string" at start of F message */
break;
/*
* 'X': frontend is exiting
*/
case '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", qtype);
break;
}
return qtype;
}
/* ----------------
* 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. EOF is returned if end of file.
* ----------------
*/
static int
ReadCommand(StringInfo inBuf)
{
int result;
if (IsUnderPostmaster)
result = SocketBackend(inBuf);
else
result = InteractiveBackend(inBuf);
return result;
}
/*
* Parse a query string and pass it through the rewriter.
*
* A list of Query nodes is returned, since the string might contain
* multiple queries and/or the rewriter might expand one query to several.
*
* NOTE: this routine is no longer used for processing interactive queries,
* but it is still needed for parsing of SQL function bodies.
*/
List *
2001-03-22 04:01:46 +00:00
pg_parse_and_rewrite(char *query_string, /* string to execute */
Oid *typev, /* parameter types */
2001-03-22 04:01:46 +00:00
int nargs) /* number of parameters */
{
List *raw_parsetree_list;
List *querytree_list;
List *list_item;
StringInfoData stri;
initStringInfo(&stri);
appendStringInfo(&stri, "%s", query_string);
/*
* (1) parse the request string into a list of raw parse trees.
*/
raw_parsetree_list = pg_parse_query(&stri, typev, nargs);
/*
* (2) Do parse analysis and rule rewrite.
*/
querytree_list = NIL;
foreach(list_item, raw_parsetree_list)
{
2001-03-22 04:01:46 +00:00
Node *parsetree = (Node *) lfirst(list_item);
querytree_list = nconc(querytree_list,
pg_analyze_and_rewrite(parsetree));
}
return querytree_list;
}
/*
* Do raw parsing (only).
*
* A list of parsetrees is returned, since there might be multiple
* commands in the given string.
*
* NOTE: for interactive queries, it is important to keep this routine
* separate from the analysis & rewrite stages. Analysis and rewriting
* cannot be done in an aborted transaction, since they require access to
* database tables. So, we rely on the raw parser to determine whether
* we've seen a COMMIT or ABORT command; when we are in abort state, other
* commands are not processed any further than the raw parse stage.
*/
List *
pg_parse_query(StringInfo query_string, Oid *typev, int nargs)
{
List *raw_parsetree_list;
if (Log_statement)
elog(LOG, "query: %s", query_string->data);
if (Show_parser_stats)
ResetUsage();
raw_parsetree_list = parser(query_string, typev, nargs);
if (Show_parser_stats)
ShowUsage("PARSER STATISTICS");
return raw_parsetree_list;
}
/*
* Given a raw parsetree (gram.y output), perform parse analysis and
* rule rewriting.
*
* A list of Query nodes is returned, since either the analyzer or the
* rewriter might expand one query to several.
*
* NOTE: for reasons mentioned above, this must be separate from raw parsing.
*/
List *
pg_analyze_and_rewrite(Node *parsetree)
{
List *querytree_list;
List *list_item;
Query *querytree;
List *new_list;
/*
* (1) Perform parse analysis.
*/
if (Show_parser_stats)
ResetUsage();
querytree_list = parse_analyze(parsetree, NULL);
if (Show_parser_stats)
{
ShowUsage("PARSE ANALYSIS STATISTICS");
ResetUsage();
}
/*
* (2) Rewrite the queries, as necessary
*
* rewritten queries are collected in new_list. Note there may be more
* or fewer than in the original list.
*/
new_list = NIL;
foreach(list_item, querytree_list)
{
querytree = (Query *) lfirst(list_item);
if (Debug_print_parse)
elog_node_display(LOG, "parse tree", querytree,
Debug_pretty_print);
if (querytree->commandType == CMD_UTILITY)
{
/* don't rewrite utilities, just dump 'em into new_list */
new_list = lappend(new_list, querytree);
}
else
{
/* rewrite regular queries */
List *rewritten = QueryRewrite(querytree);
new_list = nconc(new_list, rewritten);
}
}
querytree_list = new_list;
if (Show_parser_stats)
ShowUsage("REWRITER STATISTICS");
#ifdef COPY_PARSE_PLAN_TREES
2001-03-22 04:01:46 +00:00
/*
* Optional debugging check: pass querytree output through
* copyObject()
*/
new_list = (List *) copyObject(querytree_list);
/* This checks both copyObject() and the equal() routines... */
2001-03-22 04:01:46 +00:00
if (!equal(new_list, querytree_list))
elog(WARNING, "pg_analyze_and_rewrite: copyObject failed on parse tree");
else
querytree_list = new_list;
#endif
if (Debug_print_rewritten)
elog_node_display(LOG, "rewritten parse tree", querytree_list,
Debug_pretty_print);
return querytree_list;
}
/* Generate a plan for a single query. */
Plan *
pg_plan_query(Query *querytree)
{
Plan *plan;
/* Utility commands have no plans. */
if (querytree->commandType == CMD_UTILITY)
return NULL;
if (Show_planner_stats)
ResetUsage();
/* call the optimizer */
plan = planner(querytree);
if (Show_planner_stats)
ShowUsage("PLANNER STATISTICS");
#ifdef COPY_PARSE_PLAN_TREES
/* Optional debugging check: pass plan output through copyObject() */
{
2001-03-22 04:01:46 +00:00
Plan *new_plan = (Plan *) copyObject(plan);
2001-03-22 04:01:46 +00:00
/*
* equal() currently does not have routines to compare Plan nodes,
* so don't try to test equality here. Perhaps fix someday?
*/
#ifdef NOT_USED
/* This checks both copyObject() and the equal() routines... */
2001-03-22 04:01:46 +00:00
if (!equal(new_plan, plan))
elog(WARNING, "pg_plan_query: copyObject failed on plan tree");
else
#endif
plan = new_plan;
}
#endif
/*
* Print plan if debugging.
*/
if (Debug_print_plan)
elog_node_display(LOG, "plan", plan, Debug_pretty_print);
This is the final state of the rule system for 6.4 after the patch is applied: Rewrite rules on relation level work fine now. Event qualifications on insert/update/delete rules work fine now. I added the new keyword OLD to reference the CURRENT tuple. CURRENT will be removed in 6.5. Update rules can reference NEW and OLD in the rule qualification and the actions. Insert/update/delete rules on views can be established to let them behave like real tables. For insert/update/delete rules multiple actions are supported now. The actions can also be surrounded by parantheses to make psql happy. Multiple actions are required if update to a view requires updates to multiple tables. Regular users are permitted to create/drop rules on tables they have RULE permissions for (DefineQueryRewrite() is now able to get around the access restrictions on pg_rewrite). This enables view creation for regular users too. This required an extra boolean parameter to pg_parse_and_plan() that tells to set skipAcl on all rangetable entries of the resulting queries. There is a new function pg_exec_query_acl_override() that could be used by backend utilities to use this facility. All rule actions (not only views) inherit the permissions of the event relations owner. Sample: User A creates tables T1 and T2, creates rules that log INSERT/UPDATE/DELETE on T1 in T2 (like in the regression tests for rules I created) and grants ALL but RULE on T1 to user B. User B can now fully access T1 and the logging happens in T2. But user B cannot access T2 at all, only the rule actions can. And due to missing RULE permissions on T1, user B cannot disable logging. Rules on the attribute level are disabled (they don't work properly and since regular users are now permitted to create rules I decided to disable them). Rules on select must have exactly one action that is a select (so select rules must be a view definition). UPDATE NEW/OLD rules are disabled (still broken, but triggers can do it). There are two new system views (pg_rule and pg_view) that show the definition of the rules or views so the db admin can see what the users do. They use two new functions pg_get_ruledef() and pg_get_viewdef() that are builtins. The functions pg_get_ruledef() and pg_get_viewdef() could be used to implement rule and view support in pg_dump. PostgreSQL is now the only database system I know, that has rewrite rules on the query level. All others (where I found a rule statement at all) use stored database procedures or the like (triggers as we call them) for active rules (as some call them). Future of the rule system: The now disabled parts of the rule system (attribute level, multiple actions on select and update new stuff) require a complete new rewrite handler from scratch. The old one is too badly wired up. After 6.4 I'll start to work on a new rewrite handler, that fully supports the attribute level rules, multiple actions on select and update new. This will be available for 6.5 so we get full rewrite rule capabilities. Jan
1998-08-24 01:38:11 +00:00
return plan;
}
/* ----------------------------------------------------------------
* pg_exec_query_string()
*
* Takes a querystring, runs the parser/utilities or
* parser/planner/executor over it as necessary.
*
* Assumptions:
*
* At call, we are not inside a transaction command.
*
* The CurrentMemoryContext after starting a transaction command must be
* appropriate for execution of individual queries (typically this will be
2001-03-22 04:01:46 +00:00
* TransactionCommandContext). Note that this routine resets that context
* after each individual query, so don't store anything there that
* must outlive the call!
*
* parse_context references a context suitable for holding the
* parse/rewrite trees (typically this will be QueryContext).
* This context *must* be longer-lived than the transaction context!
* In fact, if the query string might contain BEGIN/COMMIT commands,
* parse_context had better outlive TopTransactionContext!
*
* We could have hard-wired knowledge about QueryContext and
* TransactionCommandContext into this routine, but it seems better
* not to, in case callers from outside this module need to use some
* other contexts.
*
* ----------------------------------------------------------------
*/
void
2002-09-04 20:31:48 +00:00
pg_exec_query_string(StringInfo query_string, /* string to execute */
2001-03-22 04:01:46 +00:00
CommandDest dest, /* where results should go */
MemoryContext parse_context) /* context for
* parsetrees */
{
bool xact_started;
MemoryContext oldcontext;
List *parsetree_list,
*parsetree_item;
2002-09-04 20:31:48 +00:00
struct timeval start_t,
stop_t;
bool save_Log_duration = Log_duration;
debug_query_string = query_string->data;
/*
2002-10-06 03:56:03 +00:00
* We use save_Log_duration so "SET Log_duration = true" doesn't
2002-09-04 20:31:48 +00:00
* report incorrect time because gettimeofday() wasn't called.
*/
if (save_Log_duration)
gettimeofday(&start_t, NULL);
/*
2001-03-22 04:01:46 +00:00
* Start up a transaction command. All queries generated by the
* query_string will be in this same command block, *unless* we find a
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command
* after one of those, else bad things will happen in xact.c. (Note
* that this will possibly change current memory context.)
*/
start_xact_command();
xact_started = true;
/*
2001-03-22 04:01:46 +00:00
* parse_context *must* be different from the execution memory
* context, else the context reset at the bottom of the loop will
* destroy the parsetree list. (We really ought to check that
* parse_context isn't a child of CurrentMemoryContext either, but
* that would take more cycles than it's likely to be worth.)
*/
Assert(parse_context != CurrentMemoryContext);
/*
* Switch to appropriate context for constructing parsetrees.
*/
oldcontext = MemoryContextSwitchTo(parse_context);
1999-05-25 16:15:34 +00:00
/*
2001-03-22 04:01:46 +00:00
* Do basic parsing of the query or queries (this should be safe even
* if we are in aborted transaction state!)
*/
parsetree_list = pg_parse_query(query_string, NULL, 0);
/*
* Switch back to execution context to enter the loop.
*/
MemoryContextSwitchTo(oldcontext);
/*
* Run through the parsetree(s) and process each one.
*/
foreach(parsetree_item, parsetree_list)
{
2001-03-22 04:01:46 +00:00
Node *parsetree = (Node *) lfirst(parsetree_item);
const char *commandTag;
char completionTag[COMPLETION_TAG_BUFSIZE];
CmdType origCmdType;
bool foundOriginalQuery = false;
2001-03-22 04:01:46 +00:00
List *querytree_list,
*querytree_item;
/*
2002-09-04 20:31:48 +00:00
* First we set the command-completion tag to the main query (as
* opposed to each of the others that may be generated by analyze
* and rewrite). Also set ps_status and do any special
* start-of-SQL-command processing needed by the destination.
*/
commandTag = CreateCommandTag(parsetree);
switch (nodeTag(parsetree))
{
case T_InsertStmt:
origCmdType = CMD_INSERT;
break;
case T_DeleteStmt:
origCmdType = CMD_DELETE;
break;
case T_UpdateStmt:
origCmdType = CMD_UPDATE;
break;
case T_SelectStmt:
origCmdType = CMD_SELECT;
break;
default:
/* Otherwise, never match commandType */
origCmdType = CMD_UNKNOWN;
break;
}
set_ps_display(commandTag);
BeginCommand(commandTag, dest);
/*
* If we are in an aborted transaction, ignore all commands except
* COMMIT/ABORT. It is important that this test occur before we
* try to do parse analysis, rewrite, or planning, since all those
2001-03-22 04:01:46 +00:00
* phases try to do database accesses, which may fail in abort
* state. (It might be safe to allow some additional utility
* commands in this state, but not many...)
*/
if (IsAbortedTransactionBlockState())
{
2001-03-22 04:01:46 +00:00
bool allowit = false;
if (IsA(parsetree, TransactionStmt))
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
if (stmt->command == COMMIT || stmt->command == ROLLBACK)
allowit = true;
}
2001-03-22 04:01:46 +00:00
if (!allowit)
elog(ERROR, "current transaction is aborted, "
"queries ignored until end of transaction block");
}
/* Make sure we are in a transaction command */
2001-03-22 04:01:46 +00:00
if (!xact_started)
{
start_xact_command();
xact_started = true;
}
/* If we got a cancel signal in parsing or prior command, quit */
CHECK_FOR_INTERRUPTS();
/*
* OK to analyze and rewrite this query.
*
2001-03-22 04:01:46 +00:00
* Switch to appropriate context for constructing querytrees (again,
* these must outlive the execution context).
*/
oldcontext = MemoryContextSwitchTo(parse_context);
querytree_list = pg_analyze_and_rewrite(parsetree);
1998-12-16 11:53:55 +00:00
/*
* Switch back to execution context for planning and execution.
*/
MemoryContextSwitchTo(oldcontext);
/*
* Inner loop handles the individual queries generated from a
* single parsetree by analysis and rewrite.
*/
foreach(querytree_item, querytree_list)
{
Query *querytree = (Query *) lfirst(querytree_item);
bool endTransactionBlock = false;
bool canSetTag;
/* Make sure we are in a transaction command */
2001-03-22 04:01:46 +00:00
if (!xact_started)
{
start_xact_command();
xact_started = true;
}
2001-03-22 04:01:46 +00:00
/*
* If we got a cancel signal in analysis or prior command,
* quit
*/
CHECK_FOR_INTERRUPTS();
/*
* This query can set the completion tag if it is the original
* query, or if it is an INSTEAD query of the same kind as the
* original and we haven't yet seen the original query.
*/
if (querytree->querySource == QSRC_ORIGINAL)
{
canSetTag = true;
foundOriginalQuery = true;
}
else if (!foundOriginalQuery &&
querytree->commandType == origCmdType &&
(querytree->querySource == QSRC_INSTEAD_RULE ||
querytree->querySource == QSRC_QUAL_INSTEAD_RULE))
canSetTag = true;
else
canSetTag = false;
if (querytree->commandType == CMD_UTILITY)
{
/*
* process utility functions (create, destroy, etc..)
*/
Node *utilityStmt = querytree->utilityStmt;
elog(DEBUG2, "ProcessUtility");
/*
* Set snapshot if utility stmt needs one. Most reliable
* way to do this seems to be to enumerate those that do not
* need one; this is a short list. Transaction control,
* LOCK, and SET must *not* set a snapshot since they need
* to be executable at the start of a serializable transaction
* without freezing a snapshot. By extension we allow SHOW
* not to set a snapshot. The other stmts listed are just
* efficiency hacks. Beware of listing anything that can
* modify the database --- if, say, it has to update a
* functional index, then it had better have a snapshot.
*/
if (! (IsA(utilityStmt, TransactionStmt) ||
IsA(utilityStmt, LockStmt) ||
IsA(utilityStmt, VariableSetStmt) ||
IsA(utilityStmt, VariableShowStmt) ||
IsA(utilityStmt, VariableResetStmt) ||
IsA(utilityStmt, ConstraintsSetStmt) ||
/* efficiency hacks from here down */
IsA(utilityStmt, FetchStmt) ||
IsA(utilityStmt, ListenStmt) ||
IsA(utilityStmt, NotifyStmt) ||
IsA(utilityStmt, UnlistenStmt) ||
IsA(utilityStmt, CheckPointStmt)))
SetQuerySnapshot();
/* end transaction block if transaction or variable stmt */
if (IsA(utilityStmt, TransactionStmt) ||
IsA(utilityStmt, VariableSetStmt) ||
IsA(utilityStmt, VariableShowStmt) ||
IsA(utilityStmt, VariableResetStmt))
endTransactionBlock = true;
if (canSetTag)
{
/* utility statement can override default tag string */
ProcessUtility(utilityStmt, dest, completionTag);
if (completionTag[0])
commandTag = completionTag;
}
else
{
/* utility added by rewrite cannot override tag */
ProcessUtility(utilityStmt, dest, NULL);
}
}
else
{
/*
* process a plannable query.
*/
Plan *plan;
/*
* Initialize snapshot state for query. This has to
* be done before running the planner, because it might
* try to evaluate immutable or stable functions, which
* in turn might run queries.
*/
SetQuerySnapshot();
/* Make the plan */
plan = pg_plan_query(querytree);
/* if we got a cancel signal whilst planning, quit */
CHECK_FOR_INTERRUPTS();
/*
* execute the plan
*/
if (Show_executor_stats)
ResetUsage();
if (dontExecute)
{
/* don't execute it, just show the query plan */
print_plan(plan, querytree);
}
else
{
elog(DEBUG2, "ProcessQuery");
if (canSetTag)
{
/* statement can override default tag string */
ProcessQuery(querytree, plan, dest, completionTag);
commandTag = completionTag;
}
else
{
/* stmt added by rewrite cannot override tag */
ProcessQuery(querytree, plan, dest, NULL);
}
}
if (Show_executor_stats)
ShowUsage("EXECUTOR STATISTICS");
}
/*
* In a query block, we want to increment the command counter
* between queries so that the effects of early queries are
2001-03-22 04:01:46 +00:00
* visible to subsequent ones. In particular we'd better do
* so before checking constraints.
*/
if (!endTransactionBlock)
CommandCounterIncrement();
/*
2001-03-22 04:01:46 +00:00
* Clear the execution context to recover temporary memory
* used by the query. NOTE: if query string contains
* BEGIN/COMMIT transaction commands, execution context may
2001-03-22 04:01:46 +00:00
* now be different from what we were originally passed; so be
* careful to clear current context not "oldcontext".
*/
Assert(parse_context != CurrentMemoryContext);
MemoryContextResetAndDeleteChildren(CurrentMemoryContext);
/*
* If this was a transaction control statement or a variable
* set/show/reset statement, commit it and arrange to start a
* new xact command for the next command (if any).
*/
if (endTransactionBlock)
{
finish_xact_command(true);
xact_started = false;
}
2002-09-04 20:31:48 +00:00
} /* end loop over queries generated from a
* parsetree */
/*
* If this is the last parsetree of the query string, close down
2002-09-04 20:31:48 +00:00
* transaction statement before reporting command-complete. This
* is so that any end-of-transaction errors are reported before
* the command-complete message is issued, to avoid confusing
* clients who will expect either a command-complete message or an
* error, not one and then the other. But for compatibility with
* historical Postgres behavior, we do not force a transaction
* boundary between queries appearing in a single query string.
*/
if (lnext(parsetree_item) == NIL && xact_started)
{
finish_xact_command(false);
xact_started = false;
}
/*
2002-09-04 20:31:48 +00:00
* It is possible that the original query was removed due to a DO
* INSTEAD rewrite rule. If so, and if we found no INSTEAD query
* matching the command type, we will still have the default
* completion tag. This is fine for most purposes, but it
2002-09-04 20:31:48 +00:00
* may confuse clients if it's INSERT/UPDATE/DELETE. Clients
* expect those tags to have counts after them (cf. ProcessQuery).
*/
if (!foundOriginalQuery)
{
if (strcmp(commandTag, "INSERT") == 0)
commandTag = "INSERT 0 0";
else if (strcmp(commandTag, "UPDATE") == 0)
commandTag = "UPDATE 0";
else if (strcmp(commandTag, "DELETE") == 0)
commandTag = "DELETE 0";
}
/*
* Tell client that we're done with this query. Note we emit
2002-09-04 20:31:48 +00:00
* exactly one EndCommand report for each raw parsetree, thus one
* for each SQL command the client sent, regardless of rewriting.
* (But a command aborted by error will not send an EndCommand
* report at all.)
*/
EndCommand(commandTag, dest);
2001-03-22 04:01:46 +00:00
} /* end loop over parsetrees */
/*
2002-09-04 20:31:48 +00:00
* Close down transaction statement, if one is open. (Note that this
* will only happen if the querystring was empty.)
*/
if (xact_started)
finish_xact_command(false);
if (save_Log_duration)
{
gettimeofday(&stop_t, NULL);
if (stop_t.tv_usec < start_t.tv_usec)
{
stop_t.tv_sec--;
stop_t.tv_usec += 1000000;
}
elog(LOG, "duration: %ld.%06ld sec",
(long) (stop_t.tv_sec - start_t.tv_sec),
(long) (stop_t.tv_usec - start_t.tv_usec));
}
debug_query_string = NULL;
}
/*
* Convenience routines for starting/committing a single command.
*/
static void
start_xact_command(void)
{
elog(DEBUG1, "StartTransactionCommand");
StartTransactionCommand(false);
/* Set statement timeout running, if any */
if (StatementTimeout > 0)
enable_sig_alarm(StatementTimeout, true);
}
static void
finish_xact_command(bool forceCommit)
{
/* Invoke IMMEDIATE constraint triggers */
DeferredTriggerEndQuery();
/* Cancel any active statement timeout before committing */
disable_sig_alarm(true);
/* Now commit the command */
elog(DEBUG1, "CommitTransactionCommand");
CommitTransactionCommand(forceCommit);
#ifdef SHOW_MEMORY_STATS
/* Print mem stats at each commit for leak tracking */
if (ShowStats)
MemoryContextStats(TopMemoryContext);
#endif
}
/* --------------------------------
* signal handler routines used in PostgresMain()
* --------------------------------
*/
/*
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
* quickdie() occurs when signalled SIGQUIT by the postmaster.
*
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*/
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
void
quickdie(SIGNAL_ARGS)
{
PG_SETMASK(&BlockSig);
elog(WARNING, "Message from PostgreSQL backend:"
"\n\tThe Postmaster has informed me that some other backend"
"\n\tdied abnormally and possibly corrupted shared memory."
"\n\tI have rolled back the current transaction and am"
"\n\tgoing to terminate your database system connection and exit."
"\n\tPlease reconnect to the database system and repeat your query.");
/*
* DO NOT proc_exit() -- we're here because shared memory may be
* corrupted, so we don't want to try to clean up our transaction.
* Just nail the windows shut and get out of town.
*
2001-03-22 04:01:46 +00:00
* Note we do exit(1) not exit(0). This is to force the postmaster into
* a system reset cycle if some idiot DBA sends a manual SIGQUIT to a
* random backend. This is necessary precisely because we don't clean
* up our shared memory state.
*/
exit(1);
}
/*
* Shutdown signal from postmaster: abort transaction and exit
* at soonest convenient time
*/
void
die(SIGNAL_ARGS)
{
int save_errno = errno;
/* Don't joggle the elbow of proc_exit */
2001-03-22 04:01:46 +00:00
if (!proc_exit_inprogress)
{
InterruptPending = true;
ProcDiePending = true;
2001-03-22 04:01:46 +00:00
/*
2001-03-22 04:01:46 +00:00
* If it's safe to interrupt, and we're waiting for input or a
* lock, service the interrupt immediately
*/
if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
CritSectionCount == 0)
{
/* bump holdoff count to make ProcessInterrupts() a no-op */
/* until we are done getting ready for it */
InterruptHoldoffCount++;
DisableNotifyInterrupt();
/* Make sure CheckDeadLock won't run while shutting down... */
LockWaitCancel();
InterruptHoldoffCount--;
ProcessInterrupts();
}
}
errno = save_errno;
}
/*
* Timeout or shutdown signal from postmaster during client authentication.
* Simply exit(0).
*
* XXX: possible future improvement: try to send a message indicating
* why we are disconnecting. Problem is to be sure we don't block while
* doing so, nor mess up the authentication message exchange.
*/
void
authdie(SIGNAL_ARGS)
{
exit(0);
}
/*
* Query-cancel signal from postmaster: abort current transaction
* at soonest convenient time
*/
static void
StatementCancelHandler(SIGNAL_ARGS)
{
int save_errno = errno;
2001-03-22 04:01:46 +00:00
/*
* Don't joggle the elbow of proc_exit, nor an already-in-progress
* abort
*/
if (!proc_exit_inprogress && !InError)
{
InterruptPending = true;
QueryCancelPending = true;
2001-03-22 04:01:46 +00:00
/*
* If it's safe to interrupt, and we're waiting for a lock,
2001-03-22 04:01:46 +00:00
* service the interrupt immediately. No point in interrupting if
* we're waiting for input, however.
*/
if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
CritSectionCount == 0)
{
/* bump holdoff count to make ProcessInterrupts() a no-op */
/* until we are done getting ready for it */
InterruptHoldoffCount++;
if (LockWaitCancel())
{
DisableNotifyInterrupt();
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
InterruptHoldoffCount--;
ProcessInterrupts();
}
else
InterruptHoldoffCount--;
}
}
errno = save_errno;
}
/* signal handler for floating point exception */
static void
FloatExceptionHandler(SIGNAL_ARGS)
{
elog(ERROR, "floating point exception!"
" The last floating point operation either exceeded legal ranges"
" or was a divide by zero");
}
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
SigHupHandler(SIGNAL_ARGS)
{
got_SIGHUP = true;
}
/*
* ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
*
* If an interrupt condition is pending, and it's safe to service it,
* then clear the flag and accept the interrupt. Called only when
* InterruptPending is true.
*/
void
ProcessInterrupts(void)
{
/* OK to accept interrupt now? */
if (InterruptHoldoffCount != 0 || CritSectionCount != 0)
return;
InterruptPending = false;
if (ProcDiePending)
{
ProcDiePending = false;
2001-03-22 04:01:46 +00:00
QueryCancelPending = false; /* ProcDie trumps QueryCancel */
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
2001-03-26 17:00:54 +00:00
elog(FATAL, "This connection has been terminated by the administrator.");
}
if (QueryCancelPending)
{
QueryCancelPending = false;
2001-03-22 04:01:46 +00:00
ImmediateInterruptOK = false; /* not idle anymore */
DisableNotifyInterrupt();
elog(ERROR, "Query was cancelled.");
}
/* If we get here, do nothing (probably, QueryCancelPending was reset) */
}
static void
usage(char *progname)
{
printf("%s is the PostgreSQL stand-alone backend. It is not\nintended to be used by normal users.\n\n", progname);
2002-10-18 22:05:36 +00:00
printf("Usage:\n %s [OPTION]... [DBNAME]\n\n", progname);
printf("Options:\n");
#ifdef USE_ASSERT_CHECKING
printf(" -A 1|0 enable/disable run-time assert checking\n");
#endif
printf(" -B NBUFFERS number of shared buffers (default %d)\n", DEF_NBUFFERS);
printf(" -c NAME=VALUE set run-time parameter\n");
2002-10-18 22:05:36 +00:00
printf(" -d 0-5 debugging level (0 is off)\n");
printf(" -D DATADIR database directory\n");
printf(" -e use European date format\n");
printf(" -E echo query before execution\n");
printf(" -F turn fsync off\n");
printf(" -N do not use newline as interactive query delimiter\n");
printf(" -o FILENAME send stdout and stderr to given file\n");
2001-03-22 04:01:46 +00:00
printf(" -P disable system indexes\n");
printf(" -s show statistics after each query\n");
printf(" -S SORT-MEM set amount of memory for sorts (in kbytes)\n");
2002-10-18 22:05:36 +00:00
printf(" --help show this help, then exit\n");
printf(" --version output version information, then exit\n");
printf("\nDeveloper options:\n");
printf(" -f s|i|n|m|h forbid use of some plan types\n");
printf(" -i do not execute queries\n");
printf(" -O allow system table structure changes\n");
2002-10-18 22:05:36 +00:00
printf(" -t pa|pl|ex show timings after each query\n");
printf(" -W NUM wait NUM seconds to allow attach from a debugger\n");
printf("\nReport bugs to <pgsql-bugs@postgresql.org>.\n");
}
/* ----------------------------------------------------------------
* PostgresMain
2001-03-22 04:01:46 +00:00
* postgres main loop -- all backends, interactive or otherwise start here
*
* argc/argv are the command line arguments to be used. (When being forked
* by the postmaster, these are not the original argv array of the process.)
* username is the (possibly authenticated) PostgreSQL user name to be used
* for the session.
* ----------------------------------------------------------------
*/
int
PostgresMain(int argc, char *argv[], const char *username)
{
int flag;
2001-03-22 04:01:46 +00:00
const char *DBName = NULL;
bool secure;
int errs = 0;
int debug_flag = 0;
GucContext ctx;
GucSource gucsource;
char *tmp;
int firstchar;
StringInfo parser_input;
2001-03-22 04:01:46 +00:00
char *potential_DataDir = NULL;
/*
2001-03-22 04:01:46 +00:00
* Catch standard options before doing much else. This even works on
* systems without getopt_long.
*/
if (!IsUnderPostmaster && argc > 1)
{
2001-03-22 04:01:46 +00:00
if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-?") == 0)
{
usage(argv[0]);
exit(0);
}
2001-03-22 04:01:46 +00:00
if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-V") == 0)
{
puts("postgres (PostgreSQL) " PG_VERSION);
exit(0);
}
2001-03-22 04:01:46 +00:00
}
/*
* initialize globals (already done if under postmaster, but not if
* standalone; cheap enough to do over)
*/
MyProcPid = getpid();
/*
* Fire up essential subsystems: error and memory management
*
* If we are running under the postmaster, this is done already.
*/
if (!IsUnderPostmaster)
MemoryContextInit();
set_ps_display("startup");
SetProcessingMode(InitProcessing);
/*
* Set default values for command-line options.
*/
Noversion = false;
EchoQuery = false;
if (!IsUnderPostmaster)
{
InitializeGUCOptions();
potential_DataDir = getenv("PGDATA");
}
/* ----------------
* parse command line arguments
*
* There are now two styles of command line layout for the backend:
*
* For interactive use (not started from postmaster) the format is
* postgres [switches] [databasename]
* If the databasename is omitted it is taken to be the user name.
*
* When started from the postmaster, the format is
* postgres [secure switches] -p databasename [insecure switches]
* Switches appearing after -p came from the client (via "options"
* field of connection request). For security reasons we restrict
* what these switches can do.
* ----------------
*/
/* all options are allowed until '-p' */
secure = true;
ctx = PGC_POSTMASTER;
gucsource = PGC_S_ARGV; /* initial switches came from command line */
while ((flag = getopt(argc, argv, "A:B:c:CD:d:Eef:FiNOPo:p:S:st:v:W:x:-:")) != -1)
switch (flag)
{
case 'A':
#ifdef USE_ASSERT_CHECKING
SetConfigOption("debug_assertions", optarg, ctx, gucsource);
#else
elog(WARNING, "Assert checking is not compiled in");
#endif
break;
case 'B':
/*
* specify the size of buffer pool
*/
SetConfigOption("shared_buffers", optarg, ctx, gucsource);
break;
case 'C':
/*
* don't print version string
*/
Noversion = true;
break;
case 'D': /* PGDATA directory */
if (secure)
potential_DataDir = optarg;
break;
case 'd': /* debug level */
{
debug_flag = atoi(optarg);
/* Set server debugging level. */
if (atoi(optarg) != 0)
{
2002-09-04 20:31:48 +00:00
char *debugstr = palloc(strlen("debug") + strlen(optarg) + 1);
sprintf(debugstr, "debug%s", optarg);
SetConfigOption("log_min_messages", debugstr, ctx, gucsource);
pfree(debugstr);
2002-09-04 20:31:48 +00:00
}
else
/*
* -d0 allows user to prevent postmaster debug
* from propagating to backend. It would be nice
* to set it to the postgresql.conf value here.
*/
SetConfigOption("log_min_messages", "notice",
ctx, gucsource);
}
break;
case 'E':
/*
* E - echo the query the user entered
*/
EchoQuery = true;
break;
case 'e':
/*
* Use european date formats.
*/
SetConfigOption("datestyle", "euro", ctx, gucsource);
break;
case 'F':
/*
* turn off fsync
*/
SetConfigOption("fsync", "false", ctx, gucsource);
break;
case 'f':
/*
* f - forbid generation of certain plans
*/
tmp = NULL;
switch (optarg[0])
{
case 's': /* seqscan */
tmp = "enable_seqscan";
break;
case 'i': /* indexscan */
tmp = "enable_indexscan";
break;
case 't': /* tidscan */
tmp = "enable_tidscan";
break;
case 'n': /* nestloop */
tmp = "enable_nestloop";
break;
case 'm': /* mergejoin */
tmp = "enable_mergejoin";
break;
case 'h': /* hashjoin */
tmp = "enable_hashjoin";
break;
default:
errs++;
}
if (tmp)
SetConfigOption(tmp, "false", ctx, gucsource);
break;
case 'i':
dontExecute = true;
break;
case 'N':
/*
* N - Don't use newline as a query delimiter
*/
UseNewLine = 0;
break;
case 'O':
/*
* allow system table structure modifications
*/
if (secure) /* XXX safe to allow from client??? */
allowSystemTableMods = true;
break;
2000-02-18 09:30:20 +00:00
case 'P':
/*
* ignore system indexes
2000-02-18 09:30:20 +00:00
*/
if (secure) /* XXX safe to allow from client??? */
IgnoreSystemIndexes(true);
break;
1999-05-01 17:16:25 +00:00
case 'o':
/*
* o - send output (stdout and stderr) to the given file
1999-05-01 17:16:25 +00:00
*/
if (secure)
StrNCpy(OutputFileName, optarg, MAXPGPATH);
1999-05-01 17:16:25 +00:00
break;
case 'p':
/*
* p - special flag passed if backend was forked by a
* postmaster.
*/
if (secure)
{
DBName = strdup(optarg);
1999-05-25 16:15:34 +00:00
secure = false; /* subsequent switches are NOT
* secure */
ctx = PGC_BACKEND;
gucsource = PGC_S_CLIENT;
}
break;
case 'S':
/*
* S - amount of sort memory to use in 1k bytes
*/
SetConfigOption("sort_mem", optarg, ctx, gucsource);
break;
case 's':
/*
* s - report usage statistics (timings) after each query
*/
SetConfigOption("show_statement_stats", "true", ctx, gucsource);
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.
* ----------------
*/
tmp = NULL;
switch (optarg[0])
{
case 'p':
if (optarg[1] == 'a')
tmp = "show_parser_stats";
else if (optarg[1] == 'l')
tmp = "show_planner_stats";
else
errs++;
break;
case 'e':
tmp = "show_executor_stats";
break;
default:
errs++;
break;
}
if (tmp)
SetConfigOption(tmp, "true", ctx, gucsource);
break;
case 'v':
if (secure)
FrontendProtocol = (ProtocolVersion) atoi(optarg);
break;
case 'W':
/*
* wait N seconds to allow attach from a debugger
*/
sleep(atoi(optarg));
break;
case 'x':
1999-05-25 16:15:34 +00:00
#ifdef NOT_USED /* planner/xfunc.h */
/*
* control joey hellerstein's expensive function
* optimization
*/
if (XfuncMode != 0)
{
elog(WARNING, "only one -x flag is allowed");
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
{
elog(WARNING, "use -x {off,nor,nopull,nopm,pullall,wait}");
errs++;
}
#endif
break;
case 'c':
case '-':
{
2001-03-22 04:01:46 +00:00
char *name,
*value;
2001-03-22 04:01:46 +00:00
ParseLongOption(optarg, &name, &value);
if (!value)
{
if (flag == '-')
elog(ERROR, "--%s requires argument", optarg);
else
elog(ERROR, "-c %s requires argument", optarg);
}
SetConfigOption(name, value, ctx, gucsource);
2001-03-22 04:01:46 +00:00
free(name);
if (value)
free(value);
break;
}
default:
errs++;
1999-05-01 17:16:25 +00:00
break;
}
/*
* -d is not the same as setting
* log_min_messages because it enables other
* output options.
*/
if (debug_flag >= 1)
SetConfigOption("log_connections", "true", ctx, gucsource);
if (debug_flag >= 2)
SetConfigOption("log_statement", "true", ctx, gucsource);
if (debug_flag >= 3)
SetConfigOption("debug_print_parse", "true", ctx, gucsource);
if (debug_flag >= 4)
SetConfigOption("debug_print_plan", "true", ctx, gucsource);
if (debug_flag >= 5)
SetConfigOption("debug_print_rewritten", "true", ctx, gucsource);
/*
* Post-processing for command line options.
*/
if (Show_statement_stats &&
(Show_parser_stats || Show_planner_stats || Show_executor_stats))
{
elog(WARNING, "Query statistics are disabled because parser, planner, or executor statistics are on.");
SetConfigOption("show_statement_stats", "false", ctx, gucsource);
}
if (!IsUnderPostmaster)
{
if (!potential_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]);
proc_exit(1);
}
SetDataDir(potential_DataDir);
}
Assert(DataDir);
/*
* Set up signal handlers and masks.
*
* Note that postmaster blocked all signals before forking child process,
2001-03-22 04:01:46 +00:00
* so there is no race condition whereby we might receive a signal
* before we have set up the handler.
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
*
* Also note: it's best not to use any signals that are SIG_IGNored in
2001-03-22 04:01:46 +00:00
* the postmaster. If such a signal arrives before we are able to
* change the handler to non-SIG_IGN, it'll get dropped. Instead,
2002-09-04 20:31:48 +00:00
* make a dummy handler in the postmaster to reserve the signal. (Of
* course, this isn't an issue for signals that are locally generated,
* such as SIGALRM and SIGPIPE.)
*/
pqsignal(SIGHUP, SigHupHandler); /* set flag to read config file */
2002-09-04 20:31:48 +00:00
pqsignal(SIGINT, StatementCancelHandler); /* cancel current query */
pqsignal(SIGTERM, die); /* cancel current query and exit */
pqsignal(SIGQUIT, quickdie); /* hard crash time */
pqsignal(SIGALRM, handle_sig_alarm); /* timeout conditions */
/*
* Ignore failure to write to frontend. Note: if frontend closes
* connection, we will notice it and exit cleanly when control next
* returns to outer loop. This seems safer than forcing exit in the
* midst of output during who-knows-what operation...
*/
pqsignal(SIGPIPE, SIG_IGN);
2001-03-22 04:01:46 +00:00
pqsignal(SIGUSR1, SIG_IGN); /* this signal available for use */
pqsignal(SIGUSR2, Async_NotifyHandler); /* flush also sinval cache */
pqsignal(SIGFPE, FloatExceptionHandler);
/*
2001-03-22 04:01:46 +00:00
* Reset some signals that are accepted by postmaster but not by
* backend
*/
pqsignal(SIGCHLD, SIG_DFL); /* system() requires this on some
* platforms */
pqinitmask();
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
/* We allow SIGQUIT (quickdie) at all times */
#ifdef HAVE_SIGPROCMASK
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
sigdelset(&BlockSig, SIGQUIT);
#else
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
BlockSig &= ~(sigmask(SIGQUIT));
#endif
XLOG (and related) changes: * Store two past checkpoint locations, not just one, in pg_control. On startup, we fall back to the older checkpoint if the newer one is unreadable. Also, a physical copy of the newest checkpoint record is kept in pg_control for possible use in disaster recovery (ie, complete loss of pg_xlog). Also add a version number for pg_control itself. Remove archdir from pg_control; it ought to be a GUC parameter, not a special case (not that it's implemented yet anyway). * Suppress successive checkpoint records when nothing has been entered in the WAL log since the last one. This is not so much to avoid I/O as to make it actually useful to keep track of the last two checkpoints. If the things are right next to each other then there's not a lot of redundancy gained... * Change CRC scheme to a true 64-bit CRC, not a pair of 32-bit CRCs on alternate bytes. Polynomial borrowed from ECMA DLT1 standard. * Fix XLOG record length handling so that it will work at BLCKSZ = 32k. * Change XID allocation to work more like OID allocation. (This is of dubious necessity, but I think it's a good idea anyway.) * Fix a number of minor bugs, such as off-by-one logic for XLOG file wraparound at the 4 gig mark. * Add documentation and clean up some coding infelicities; move file format declarations out to include files where planned contrib utilities can get at them. * Checkpoint will now occur every CHECKPOINT_SEGMENTS log segments or every CHECKPOINT_TIMEOUT seconds, whichever comes first. It is also possible to force a checkpoint by sending SIGUSR1 to the postmaster (undocumented feature...) * Defend against kill -9 postmaster by storing shmem block's key and ID in postmaster.pid lockfile, and checking at startup to ensure that no processes are still connected to old shmem block (if it still exists). * Switch backends to accept SIGQUIT rather than SIGUSR1 for emergency stop, for symmetry with postmaster and xlog utilities. Clean up signal handling in bootstrap.c so that xlog utilities launched by postmaster will react to signals better. * Standalone bootstrap now grabs lockfile in target directory, as added insurance against running it in parallel with live postmaster.
2001-03-13 01:17:06 +00:00
PG_SETMASK(&BlockSig); /* block everything except SIGQUIT */
if (IsUnderPostmaster)
{
/* noninteractive case: nothing should be left after switches */
if (errs || argc != optind || DBName == NULL)
{
elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
argv[0]);
2001-03-22 04:01:46 +00:00
proc_exit(0); /* not 1, that causes system-wide
* restart... */
}
BaseInit();
}
else
{
/* interactive case: database name can be last arg on command line */
if (errs || argc - optind > 1)
{
elog(WARNING, "%s: invalid command line arguments\nTry -? for help.",
argv[0]);
proc_exit(1);
}
else if (argc - optind == 1)
DBName = argv[optind];
else if ((DBName = username) == NULL)
{
elog(WARNING, "%s: user name undefined and no database specified",
argv[0]);
proc_exit(1);
}
2000-01-09 12:17:33 +00:00
/*
* On some systems our dynloader code needs the executable's
* pathname. (If under postmaster, this was done already.)
*/
if (FindExec(pg_pathname, argv[0], "postgres") < 0)
elog(FATAL, "%s: could not locate executable, bailing out...",
argv[0]);
/*
* Validate we have been given a reasonable-looking DataDir (if
* under postmaster, assume postmaster did this already).
*/
ValidatePgVersion(DataDir);
2000-01-09 12:17:33 +00:00
/*
* Create lockfile for data directory.
2000-01-09 12:17:33 +00:00
*/
2001-03-22 04:01:46 +00:00
if (!CreateDataDirLockFile(DataDir, false))
proc_exit(1);
2000-01-09 12:17:33 +00:00
XLOGPathInit();
BaseInit();
/*
* Start up xlog for standalone backend, and register to have it
* closed down at exit.
*/
StartupXLOG();
on_shmem_exit(ShutdownXLOG, 0);
}
/*
* Set up additional info.
*/
#ifdef CYR_RECODE
SetCharSet();
#endif
/*
* General initialization.
*
* NOTE: if you are tempted to add code in this vicinity, consider
* putting it inside InitPostgres() instead. In particular, anything
* that involves database access should be there, not here.
*/
elog(DEBUG2, "InitPostgres");
InitPostgres(DBName, username);
SetProcessingMode(NormalProcessing);
/*
* Send this backend's cancellation info to the frontend.
*/
if (whereToSendOutput == Remote &&
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
StringInfoData buf;
1999-05-25 16:15:34 +00:00
pq_beginmessage(&buf);
pq_sendbyte(&buf, 'K');
pq_sendint(&buf, (int32) MyProcPid, sizeof(int32));
pq_sendint(&buf, (int32) MyCancelKey, sizeof(int32));
pq_endmessage(&buf);
/* Need not flush since ReadyForQuery will do it. */
}
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.308 $ $Date: 2002/11/14 23:53:27 $\n");
}
/*
* Create the memory context we will use in the main loop.
*
2001-03-22 04:01:46 +00:00
* QueryContext is reset once per iteration of the main loop, ie, upon
* completion of processing of each supplied query string. It can
* therefore be used for any data that should live just as long as the
* query string --- parse trees, for example.
*/
QueryContext = AllocSetContextCreate(TopMemoryContext,
"QueryContext",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
/* ----------
* Tell the statistics collector that we're alive and
* to which database we belong.
* ----------
*/
pgstat_bestart();
/*
* POSTGRES main processing loop begins here
*
* If an exception is encountered, processing resumes here so we abort
* the current transaction and start a new one.
*/
if (sigsetjmp(Warn_restart, 1) != 0)
{
/*
* NOTE: if you are tempted to add more code in this if-block,
2001-03-22 04:01:46 +00:00
* consider the probability that it should be in
* AbortTransaction() instead.
*
* Make sure we're not interrupted while cleaning up. Also forget
* any pending QueryCancel request, since we're aborting anyway.
* Force InterruptHoldoffCount to a known state in case we elog'd
* from inside a holdoff section.
*/
ImmediateInterruptOK = false;
QueryCancelPending = false;
InterruptHoldoffCount = 1;
CritSectionCount = 0; /* should be unnecessary, but... */
disable_sig_alarm(true);
QueryCancelPending = false; /* again in case timeout occurred */
DisableNotifyInterrupt();
debug_query_string = NULL;
/*
* Make sure we are in a valid memory context during recovery.
*
* We use ErrorContext in hopes that it will have some free space
* even if we're otherwise up against it...
*/
MemoryContextSwitchTo(ErrorContext);
/* Do the recovery */
elog(DEBUG1, "AbortCurrentTransaction");
AbortCurrentTransaction();
/*
* Now return to normal top-level context and clear ErrorContext
* for next time.
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext);
/*
* Clear flag to indicate that we got out of error recovery mode
* successfully. (Flag was set in elog.c before longjmp().)
*/
InError = false;
/*
* Exit interrupt holdoff section we implicitly established above.
*/
RESUME_INTERRUPTS();
}
Warn_restart_ready = true; /* we can now handle elog(ERROR) */
PG_SETMASK(&UnBlockSig);
/*
* Non-error queries loop here.
*/
for (;;)
{
/*
2001-03-22 04:01:46 +00:00
* Release storage left over from prior query cycle, and create a
* new query input buffer in the cleared QueryContext.
*/
MemoryContextSwitchTo(QueryContext);
MemoryContextResetAndDeleteChildren(QueryContext);
parser_input = makeStringInfo();
/*
* (1) tell the frontend we're ready for a new query.
*
* Note: this includes fflush()'ing the last of the prior output.
*/
ReadyForQuery(whereToSendOutput);
/* ----------
* Tell the statistics collector what we've collected
* so far.
* ----------
*/
pgstat_report_tabstat();
if (IsTransactionBlock())
{
set_ps_display("idle in transaction");
pgstat_report_activity("<IDLE> in transaction");
}
else
{
set_ps_display("idle");
pgstat_report_activity("<IDLE>");
}
/*
* (2) deal with pending asynchronous NOTIFY from other backends,
* and enable async.c's signal handler to execute NOTIFY directly.
* Then set up other stuff needed before blocking for input.
*/
2001-03-22 04:01:46 +00:00
QueryCancelPending = false; /* forget any earlier CANCEL
* signal */
EnableNotifyInterrupt();
/* Allow "die" interrupt to be processed while waiting */
ImmediateInterruptOK = true;
/* and don't forget to detect one that already arrived */
QueryCancelPending = false;
CHECK_FOR_INTERRUPTS();
/*
* (3) read a command (loop blocks here)
*/
firstchar = ReadCommand(parser_input);
/*
* (4) disable async signal conditions again.
*/
ImmediateInterruptOK = false;
2001-03-22 04:01:46 +00:00
QueryCancelPending = false; /* forget any CANCEL signal */
DisableNotifyInterrupt();
/*
* (5) check for any other interesting events that happened while
* we slept.
*/
if (got_SIGHUP)
{
got_SIGHUP = false;
ProcessConfigFile(PGC_SIGHUP);
}
/*
* (6) process the command.
*/
switch (firstchar)
{
/*
* 'F' indicates a fastpath call.
*/
case 'F':
/* ----------
* Tell the collector what we're doing
* ----------
*/
pgstat_report_activity("<FASTPATH> function call");
/* start an xact for this function invocation */
start_xact_command();
/* assume it may need a snapshot */
SetQuerySnapshot();
if (HandleFunctionRequest() == EOF)
{
/* lost frontend connection during F message input */
2002-09-04 20:31:48 +00:00
/*
2002-09-04 20:31:48 +00:00
* Reset whereToSendOutput to prevent elog from
* attempting to send any more messages to client.
*/
if (whereToSendOutput == Remote)
whereToSendOutput = None;
proc_exit(0);
}
/* commit the function-invocation transaction */
finish_xact_command(false);
break;
/*
* 'Q' indicates a user query
*/
case 'Q':
if (strspn(parser_input->data, " \t\r\n") == parser_input->len)
{
/*
* if there is nothing in the input buffer, don't
* bother trying to parse and execute anything; just
* send back a quick NullCommand response.
*/
if (IsUnderPostmaster)
NullCommand(Remote);
}
else
{
/*
* otherwise, process the input string.
*
* Note: transaction command start/end is now done within
* pg_exec_query_string(), not here.
*/
if (Show_statement_stats)
ResetUsage();
pgstat_report_activity(parser_input->data);
pg_exec_query_string(parser_input,
whereToSendOutput,
QueryContext);
if (Show_statement_stats)
ShowUsage("QUERY STATISTICS");
}
break;
/*
2002-09-04 20:31:48 +00:00
* 'X' means that the frontend is closing down the socket.
* EOF means unexpected loss of frontend connection.
* Either way, perform normal shutdown.
*/
case 'X':
case EOF:
2002-09-04 20:31:48 +00:00
/*
* Reset whereToSendOutput to prevent elog from attempting
* to send any more messages to client.
*/
if (whereToSendOutput == Remote)
whereToSendOutput = None;
2001-03-22 04:01:46 +00:00
/*
* NOTE: if you are tempted to add more code here, DON'T!
2001-03-22 04:01:46 +00:00
* Whatever you had in mind to do should be set up as an
* on_proc_exit or on_shmem_exit callback, instead.
* Otherwise it will fail to be called during other
* backend-shutdown scenarios.
*/
proc_exit(0);
default:
elog(ERROR, "unknown frontend message was received");
}
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 14:30:37 +00:00
#ifdef MEMORY_CONTEXT_CHECKING
2001-03-22 04:01:46 +00:00
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 14:30:37 +00:00
/*
* Check all memory after each backend loop. This is a rather
* weird place to do it, perhaps.
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 14:30:37 +00:00
*/
2001-03-22 04:01:46 +00:00
MemoryContextCheck(TopMemoryContext);
Here is the patch with memory leak checker. This checker allow detect in-chunk leaks, overwrite-next-chunk leaks and overwrite block-freeptr leaks. A in-chunk leak --- if something overwrite space after wanted (via palloc() size, but it is still inside chunk. For example x = palloc(12); /* create 16b chunk */ memset(x, '#', 13); this leak is in the current source total invisible, because chunk is 16b and leak is in the "align space". For this feature I add data_size to StandardChunk, and all memory which go from AllocSetAlloc() is marked as 0x7F. The MemoryContextCheck() is compiled '#ifdef USE_ASSERT_CHECKING'. I add this checking to 'tcop/postgres.c' and is active after each backend query, but it is probably not sufficient, because some MemoryContext exist only during memory processing --- will good if someone who known where it is needful (Tom:-) add it for others contexts; A problem in the current source is that we have still some malloc() allocation that is not needful and this allocation is total invisible for all context routines. For example Dllist in backend (pretty dirty it is in catcache where values in Dllist are palloc-ed, but list is malloc-ed). --- and BTW. this Dllist design stand in the way for query cache :-) Tom, if you agree I start replace some mallocs. BTW. --- Tom, have you idea for across transaction presistent allocation for SQL functions? (like regex - now it is via malloc) I almost forget. I add one if() to AllocSetAlloc(), for 'size' that are greater than ALLOC_BIGCHUNK_LIMIT is not needful check AllocSetFreeIndex(), because 'fidx' is always 'ALLOCSET_NUM_FREELISTS - 1'. It a little brisk up allocation for very large chunks. Right? Karel
2000-07-11 14:30:37 +00:00
#endif
} /* end of input-reading loop */
/* can't get here because the above loop never exits */
Assert(false);
return 1; /* keep compiler quiet */
}
#ifndef HAVE_GETRUSAGE
1999-07-16 05:23:30 +00:00
#include "rusagestub.h"
#else
#include <sys/resource.h>
#endif /* HAVE_GETRUSAGE */
struct rusage Save_r;
struct timeval Save_t;
void
ResetUsage(void)
{
getrusage(RUSAGE_SELF, &Save_r);
gettimeofday(&Save_t, NULL);
ResetBufferUsage();
/* ResetTupleCount(); */
}
void
ShowUsage(const char *title)
{
StringInfoData str;
struct timeval user,
sys;
struct timeval elapse_t;
struct rusage r;
2002-09-04 20:31:48 +00:00
char *bufusage;
getrusage(RUSAGE_SELF, &r);
gettimeofday(&elapse_t, NULL);
memcpy((char *) &user, (char *) &r.ru_utime, sizeof(user));
memcpy((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.
*/
initStringInfo(&str);
appendStringInfo(&str, "! system usage stats:\n");
appendStringInfo(&str,
"!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n",
(long) (elapse_t.tv_sec - Save_t.tv_sec),
(long) (elapse_t.tv_usec - Save_t.tv_usec),
(long) (r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec),
(long) (r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec),
(long) (r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec),
(long) (r.ru_stime.tv_usec - Save_r.ru_stime.tv_usec));
appendStringInfo(&str,
2002-09-04 20:31:48 +00:00
"!\t[%ld.%06ld user %ld.%06ld sys total]\n",
(long) user.tv_sec,
(long) user.tv_usec,
(long) sys.tv_sec,
(long) sys.tv_usec);
/* BeOS has rusage but only has some fields, and not these... */
#if defined(HAVE_GETRUSAGE)
appendStringInfo(&str,
2002-09-04 20:31:48 +00:00
"!\t%ld/%ld [%ld/%ld] filesystem blocks in/out\n",
r.ru_inblock - Save_r.ru_inblock,
/* they only drink coffee at dec */
2002-09-04 20:31:48 +00:00
r.ru_oublock - Save_r.ru_oublock,
r.ru_inblock, r.ru_oublock);
appendStringInfo(&str,
"!\t%ld/%ld [%ld/%ld] page faults/reclaims, %ld [%ld] swaps\n",
2002-09-04 20:31:48 +00:00
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);
appendStringInfo(&str,
"!\t%ld [%ld] signals rcvd, %ld/%ld [%ld/%ld] messages rcvd/sent\n",
2002-09-04 20:31:48 +00:00
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);
appendStringInfo(&str,
"!\t%ld/%ld [%ld/%ld] voluntary/involuntary context switches\n",
2002-09-04 20:31:48 +00:00
r.ru_nvcsw - Save_r.ru_nvcsw,
r.ru_nivcsw - Save_r.ru_nivcsw,
r.ru_nvcsw, r.ru_nivcsw);
#endif /* HAVE_GETRUSAGE */
bufusage = ShowBufferUsage();
appendStringInfo(&str, "! buffer usage stats:\n%s", bufusage);
pfree(bufusage);
/* remove trailing newline */
2002-09-04 20:31:48 +00:00
if (str.data[str.len - 1] == '\n')
str.data[--str.len] = '\0';
elog(LOG, "%s\n%s", title, str.data);
pfree(str.data);
}
/* ----------------------------------------------------------------
* CreateCommandTag
*
* utility to get a string representation of the
* command operation.
* ----------------------------------------------------------------
*/
static const char *
CreateCommandTag(Node *parsetree)
{
2002-09-04 20:31:48 +00:00
const char *tag;
switch (nodeTag(parsetree))
{
case T_InsertStmt:
tag = "INSERT";
break;
case T_DeleteStmt:
tag = "DELETE";
break;
case T_UpdateStmt:
tag = "UPDATE";
break;
case T_SelectStmt:
tag = "SELECT";
break;
case T_TransactionStmt:
{
TransactionStmt *stmt = (TransactionStmt *) parsetree;
switch (stmt->command)
{
case BEGIN_TRANS:
tag = "BEGIN";
break;
case START:
tag = "START TRANSACTION";
break;
case COMMIT:
tag = "COMMIT";
break;
case ROLLBACK:
tag = "ROLLBACK";
break;
default:
tag = "???";
break;
}
}
break;
case T_ClosePortalStmt:
tag = "CLOSE CURSOR";
break;
case T_FetchStmt:
{
FetchStmt *stmt = (FetchStmt *) parsetree;
2002-09-04 20:31:48 +00:00
tag = (stmt->ismove) ? "MOVE" : "FETCH";
}
break;
case T_CreateDomainStmt:
tag = "CREATE DOMAIN";
2002-03-19 12:52:22 +00:00
break;
case T_CreateSchemaStmt:
tag = "CREATE SCHEMA";
break;
case T_CreateStmt:
tag = "CREATE TABLE";
break;
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
case DROP_TABLE:
tag = "DROP TABLE";
break;
case DROP_SEQUENCE:
tag = "DROP SEQUENCE";
break;
case DROP_VIEW:
tag = "DROP VIEW";
break;
case DROP_INDEX:
tag = "DROP INDEX";
break;
case DROP_TYPE:
tag = "DROP TYPE";
break;
case DROP_DOMAIN:
tag = "DROP DOMAIN";
break;
case DROP_CONVERSION:
tag = "DROP CONVERSION";
break;
case DROP_SCHEMA:
tag = "DROP SCHEMA";
break;
default:
tag = "???";
}
break;
case T_TruncateStmt:
tag = "TRUNCATE TABLE";
break;
case T_CommentStmt:
tag = "COMMENT";
break;
case T_CopyStmt:
tag = "COPY";
break;
case T_RenameStmt:
2002-09-04 20:31:48 +00:00
if (((RenameStmt *) parsetree)->renameType == RENAME_TRIGGER)
tag = "ALTER TRIGGER";
else
tag = "ALTER TABLE";
break;
case T_AlterTableStmt:
tag = "ALTER TABLE";
break;
case T_GrantStmt:
{
GrantStmt *stmt = (GrantStmt *) parsetree;
2002-09-04 20:31:48 +00:00
tag = (stmt->is_grant) ? "GRANT" : "REVOKE";
}
break;
case T_DefineStmt:
switch (((DefineStmt *) parsetree)->defType)
{
case AGGREGATE:
tag = "CREATE AGGREGATE";
break;
case OPERATOR:
tag = "CREATE OPERATOR";
break;
case TYPE_P:
tag = "CREATE TYPE";
break;
default:
tag = "???";
}
break;
case T_CompositeTypeStmt:
tag = "CREATE TYPE";
break;
case T_ViewStmt:
tag = "CREATE VIEW";
break;
case T_CreateFunctionStmt:
tag = "CREATE FUNCTION";
break;
case T_IndexStmt:
tag = "CREATE INDEX";
break;
case T_RuleStmt:
tag = "CREATE RULE";
break;
case T_CreateSeqStmt:
tag = "CREATE SEQUENCE";
break;
case T_RemoveAggrStmt:
tag = "DROP AGGREGATE";
break;
case T_RemoveFuncStmt:
tag = "DROP FUNCTION";
break;
case T_RemoveOperStmt:
tag = "DROP OPERATOR";
break;
case T_CreatedbStmt:
tag = "CREATE DATABASE";
break;
case T_AlterDatabaseSetStmt:
tag = "ALTER DATABASE";
break;
case T_DropdbStmt:
tag = "DROP DATABASE";
break;
case T_NotifyStmt:
tag = "NOTIFY";
break;
case T_ListenStmt:
tag = "LISTEN";
break;
case T_UnlistenStmt:
tag = "UNLISTEN";
break;
case T_LoadStmt:
tag = "LOAD";
break;
case T_ClusterStmt:
tag = "CLUSTER";
break;
case T_VacuumStmt:
if (((VacuumStmt *) parsetree)->vacuum)
tag = "VACUUM";
else
tag = "ANALYZE";
break;
case T_ExplainStmt:
tag = "EXPLAIN";
break;
case T_VariableSetStmt:
tag = "SET";
break;
case T_VariableShowStmt:
tag = "SHOW";
break;
case T_VariableResetStmt:
tag = "RESET";
break;
case T_CreateTrigStmt:
tag = "CREATE TRIGGER";
break;
case T_DropPropertyStmt:
switch (((DropPropertyStmt *) parsetree)->removeType)
{
case DROP_TRIGGER:
tag = "DROP TRIGGER";
break;
case DROP_RULE:
tag = "DROP RULE";
break;
default:
tag = "???";
}
break;
case T_CreatePLangStmt:
tag = "CREATE LANGUAGE";
break;
case T_DropPLangStmt:
tag = "DROP LANGUAGE";
break;
case T_CreateUserStmt:
tag = "CREATE USER";
break;
case T_AlterUserStmt:
tag = "ALTER USER";
break;
case T_AlterUserSetStmt:
tag = "ALTER USER";
break;
case T_DropUserStmt:
tag = "DROP USER";
break;
case T_LockStmt:
tag = "LOCK TABLE";
break;
case T_ConstraintsSetStmt:
tag = "SET CONSTRAINTS";
break;
case T_CreateGroupStmt:
tag = "CREATE GROUP";
break;
case T_AlterGroupStmt:
tag = "ALTER GROUP";
break;
case T_DropGroupStmt:
tag = "DROP GROUP";
break;
case T_CheckPointStmt:
tag = "CHECKPOINT";
break;
case T_ReindexStmt:
tag = "REINDEX";
break;
case T_CreateConversionStmt:
tag = "CREATE CONVERSION";
break;
case T_CreateCastStmt:
tag = "CREATE CAST";
break;
case T_DropCastStmt:
tag = "DROP CAST";
break;
case T_CreateOpClassStmt:
tag = "CREATE OPERATOR CLASS";
break;
case T_RemoveOpClassStmt:
tag = "DROP OPERATOR CLASS";
break;
case T_PrepareStmt:
tag = "PREPARE";
break;
case T_ExecuteStmt:
tag = "EXECUTE";
break;
case T_DeallocateStmt:
tag = "DEALLOCATE";
break;
default:
elog(LOG, "CreateCommandTag: unknown parse node type %d",
nodeTag(parsetree));
tag = "???";
break;
}
return tag;
}