postgresql/src/backend/tcop/postgres.c

1685 lines
38 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* postgres.c--
* POSTGRES C Backend Interface
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.85 1998/08/25 21:04:38 scrappy Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
* hence the main module of the "traffic cop".
*
*-------------------------------------------------------------------------
*/
1996-11-08 07:02:30 +01:00
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <time.h>
1996-11-08 07:02:30 +01:00
#include <setjmp.h>
#include <sys/time.h>
1996-11-08 07:02:30 +01:00
#include <sys/types.h>
#include <fcntl.h>
#include <sys/param.h> /* for MAXHOSTNAMELEN on most */
#ifndef MAXHOSTNAMELEN
#include <netdb.h> /* for MAXHOSTNAMELEN on some */
#endif
#ifndef MAXHOSTNAMELEN /* for MAXHOSTNAMELEN under sco3.2v5.0.2 */
1997-07-28 02:57:08 +02:00
#include <sys/socket.h>
#endif
#include <errno.h>
#if HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif /* aix */
#include "postgres.h"
#include "miscadmin.h"
#include "fmgr.h"
#include "access/xact.h"
#include "catalog/catname.h"
#include "commands/async.h"
#include "executor/execdebug.h"
#include "executor/executor.h"
#include "libpq/libpq.h"
#include "libpq/libpq-be.h"
#include "libpq/pqsignal.h"
#include "nodes/pg_list.h"
#include "nodes/print.h"
#include "optimizer/cost.h"
#include "optimizer/planner.h"
#include "optimizer/prep.h"
#include "parser/parser.h"
#include "rewrite/rewriteHandler.h" /* for QueryRewrite() */
#include "storage/bufmgr.h"
#include "tcop/dest.h"
#include "tcop/fastpath.h"
#include "tcop/pquery.h"
#include "tcop/tcopdebug.h"
#include "tcop/tcopprot.h" /* where declarations for this file go */
#include "tcop/utility.h"
#include "utils/mcxt.h"
#include "utils/rel.h"
#if FALSE
#include "nodes/relation.h"
#endif
#if 0
#include "optimizer/xfunc.h"
#endif
#if FALSE
#include "nodes/plannodes.h"
#endif
#if FALSE
#include "nodes/memnodes.h"
#endif
#ifdef MULTIBYTE
#include "mb/pg_wchar.h"
#endif
/* ----------------
* 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;
const char **ps_status; /* this is our 'ps' status, argv[3] */
#ifdef LOCK_MGR_DEBUG
extern int lockDebug;
#endif
extern int lockingOff;
extern int NBuffers;
int dontExecute = 0;
static int ShowStats;
static bool IsEmptyQuery = false;
char relname[80]; /* current relation name */
#if defined(nextstep)
jmp_buf Warn_restart;
#define sigsetjmp(x,y) setjmp(x)
#define siglongjmp longjmp
#else
sigjmp_buf Warn_restart;
#endif /* defined(nextstep) */
bool InError;
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;
/* ----------------
* 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 */
/* ----------------
* bushy tree plan flag: if true planner will generate bushy-tree
* plans
* ----------------
*/
int BushyPlanFlag = 0; /* default to false -- consider only
* left-deep trees */
/*
** Flags for expensive function optimization -- JMH 3/9/92
*/
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
* ----------------
*/
int _exec_repeat_ = 1;
/* ----------------------------------------------------------------
* decls for routines only used in this file
* ----------------------------------------------------------------
*/
static char InteractiveBackend(char *inBuf);
static char SocketBackend(char *inBuf);
static char ReadCommand(char *inBuf);
/* ----------------------------------------------------------------
* routines to obtain user input
* ----------------------------------------------------------------
*/
/* ----------------
* 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;
proc_exit(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
*
* 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())
* ----------------
*/
static char
SocketBackend(char *inBuf)
{
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
* ------------
*/
proc_exit(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.
* ----------------
*/
static char
ReadCommand(char *inBuf)
{
if (IsUnderPostmaster)
return SocketBackend(inBuf);
else
return InteractiveBackend(inBuf);
}
List *
pg_parse_and_plan(char *query_string, /* string to execute */
Oid *typev, /* argument types */
int nargs, /* number of arguments */
QueryTreeList **queryListP, /* pointer to the parse
* trees */
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 03:38:11 +02:00
CommandDest dest, /* where results should go */
bool aclOverride)
{
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++)
{
List *union_result,
*union_list,
*rewritten_list;
querytree = querytree_list->qtrees[i];
if (DebugPrintQuery == true)
{
printf("\n---- \tquery is:\n%s\n", query_string);
printf("\n");
fflush(stdout);
}
/* don't rewrite utilites */
if (querytree->commandType == CMD_UTILITY)
{
new_list->qtrees[j++] = querytree;
continue;
}
if (DebugPrintParse == true)
{
printf("\n---- \tparser outputs :\n");
nodeDisplay(querytree);
printf("\n");
}
/* rewrite queries (retrieve, append, delete, replace) */
rewritten = QueryRewrite(querytree);
1998-01-09 06:48:22 +01:00
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 03:38:11 +02:00
if (rewritten != NIL)
{
int len,
k;
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 03:38:11 +02:00
/*
* Rewrite the UNIONS.
*/
foreach(rewritten_list, rewritten)
{
Query *qry = (Query *) lfirst(rewritten_list);
union_result = NIL;
foreach(union_list, qry->unionClause)
union_result = nconc(union_result, QueryRewrite((Query *) lfirst(union_list)));
qry->unionClause = union_result;
}
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);
}
}
}
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 03:38:11 +02:00
/* ----------
* Due to rewriting, the new list could also have been
* shrunk (do instead nothing). Forget obsolete queries
* at the end.
* ----------
*/
new_list->len = j;
/* we're done with the original lists, free it */
free(querytree_list->qtrees);
free(querytree_list);
querytree_list = new_list;
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 03:38:11 +02:00
/*
* Override ACL checking if requested
*/
if (aclOverride) {
for (i = 0; i < querytree_list->len; i++) {
RangeTblEntry *rte;
List *l;
querytree = querytree_list->qtrees[i];
if (querytree->commandType == CMD_UTILITY)
continue;
foreach (l, querytree->rtable) {
rte = (RangeTblEntry *)lfirst(l);
rte->skipAcl = TRUE;
}
}
}
if (DebugPrintRewrittenParsetree == true)
{
printf("\n---- \tafter rewriting:\n");
for (i = 0; i < querytree_list->len; i++)
{
nodeDisplay(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");
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 03:38:11 +02:00
free(querytree_list->qtrees);
free(querytree_list);
if (queryListP)
*queryListP = (QueryTreeList *) NULL;
return (List *) NULL;
}
if (ShowPlannerStats)
ResetUsage();
/* call that optimizer */
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");
}
#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);
#endif
}
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 03:38:11 +02:00
/* ----------
* Check if the rewriting had thrown away anything
* ----------
*/
if (querytree_list->len == 0) {
free(querytree_list->qtrees);
free(querytree_list);
querytree_list = NULL;
}
if (queryListP)
*queryListP = querytree_list;
return (plan_list);
}
/* ----------------------------------------------------------------
* pg_exec_query()
*
* 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.
*
* ----------------------------------------------------------------
*/
void
pg_exec_query(char *query_string)
{
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 03:38:11 +02:00
pg_exec_query_dest(query_string, whereToSendOutput, FALSE);
}
void
pg_exec_query_acl_override(char *query_string)
{
pg_exec_query_dest(query_string, whereToSendOutput, TRUE);
}
void
pg_exec_query_dest(char *query_string, /* string to execute */
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 03:38:11 +02:00
CommandDest dest, /* where results should go */
bool aclOverride) /* to give utility
* commands power of
* superusers
*/
{
List *plan_list;
Plan *plan;
Query *querytree;
int i,
j;
QueryTreeList *querytree_list;
/* plan the queries */
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 03:38:11 +02:00
plan_list = pg_parse_and_plan(query_string, NULL, 0, &querytree_list, dest, aclOverride);
if (QueryCancel)
CancelQuery();
/* pg_parse_and_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);
#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
{
#ifndef FUNC_UTIL_PATCH
/*
* 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_parse_and_plan. DZ - 27-8-1996
*/
#else
/* ----------------
* 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, 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()
*
* handle_warn() is used to catch kill(getpid(), SIGHUP) which
* occurs when elog(ERROR) is called.
*
* quickdie() occurs when signalled by the postmaster.
* Some backend has bought the farm,
* so we need to stop what we're doing and exit.
*
* die() preforms an orderly cleanup via ExitPostgres()
* --------------------------------
*/
void
handle_warn(SIGNAL_ARGS)
{
siglongjmp(Warn_restart, 1);
}
void
quickdie(SIGNAL_ARGS)
{
elog(NOTICE, "Message from PostgreSQL backend:"
"\n\tThe Postmaster has informed me that some other backend"
" died abnormally and possibly corrupted shared memory."
"\n\tI have rolled back the current transaction and am"
" going to terminate your database system connection and exit."
"\n\tPlease reconnect to the database system and repeat your query.");
/*
* 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);
}
/* signal handler for floating point exception */
void
FloatExceptionHandler(SIGNAL_ARGS)
{
elog(ERROR, "floating point exception!"
" The last floating point operation either exceeded legal ranges"
" or was a divide by zero");
}
/* signal handler for query cancel signal from postmaster */
static void
QueryCancelHandler(SIGNAL_ARGS)
{
QueryCancel = true;
}
void
CancelQuery(void)
{
/* QueryCancel flag will be reset in main loop, which we reach by
* longjmp from elog().
*/
elog(ERROR, "Query was cancelled.");
}
static void
usage(char *progname)
{
fprintf(stderr,
1998-05-27 20:32:05 +02:00
"Usage: %s [options] [dbname]\n", progname);
#ifdef USE_ASSERT_CHECKING
fprintf(stderr, " A: enable/disable assert checking\n");
#endif
1998-05-27 20:32:05 +02:00
fprintf(stderr, "\t-B buffers\tset number of buffers in buffer pool\n");
fprintf(stderr, "\t-C \t\tsupress version info\n");
fprintf(stderr, "\t-D dir\t\tdata directory\n");
fprintf(stderr, "\t-E \t\techo query before execution\n");
fprintf(stderr, "\t-F \t\tturn off fsync\n");
#ifdef LOCK_MGR_DEBUG
1998-05-27 20:32:05 +02:00
fprintf(stderr, "\t-K \t\tset locking debug level [0|1|2]\n");
#endif
1998-05-27 20:32:05 +02:00
fprintf(stderr, "\t-P port\t\tset port file descriptor\n");
fprintf(stderr, "\t-Q \t\tsuppress informational messages\n");
fprintf(stderr, "\t-S buffers\tset amount of sort memory available\n");
fprintf(stderr, "\t-d [1|2|3]\tset debug level\n");
fprintf(stderr, "\t-e \t\tturn on European date format\n");
fprintf(stderr, "\t-o file\t\tsend stdout and stderr to given filename \n");
fprintf(stderr, "\t-s \t\tshow stats after each query\n");
fprintf(stderr, "\t-v version\tset protocol version being used by frontend\n");
fprintf(stderr, "\t-W \t\twait N seconds to allow attach from a debugger\n");
}
/* ----------------------------------------------------------------
* PostgresMain
* postgres main loop
* all backends, interactive or otherwise start here
* ----------------------------------------------------------------
*/
int
PostgresMain(int argc, char *argv[], int real_argc, char *real_argv[])
{
bool flagC = false,
flagQ = false,
flagE = false,
flagEu = false;
int flag;
char *DBName = NULL;
int errs = 0;
char firstchar;
char parser_input[MAX_PARSE_BUFFER];
char *userName;
char *DBDate = NULL;
extern int optind;
extern char *optarg;
extern short DebugLvl;
/* ----------------
* parse command line arguments
* ----------------
*/
/*
* Set default values.
*/
ShowStats = 0;
ShowParserStats = ShowPlannerStats = ShowExecutorStats = 0;
#ifdef LOCK_MGR_DEBUG
lockDebug = 0;
#endif
/*
* get hostname is either the environment variable PGHOST or NULL NULL
* means Unix-socket only
*/
DataDir = getenv("PGDATA");
/*
* Try to get initial values for date styles and formats. Does not do
* a complete job, but should be good enough for backend. Cannot call
* parse_date() since palloc/pfree memory is not set up yet.
*/
DBDate = getenv("PGDATESTYLE");
if (DBDate != NULL)
{
if (strcasecmp(DBDate, "ISO") == 0)
DateStyle = USE_ISO_DATES;
else if (strcasecmp(DBDate, "SQL") == 0)
DateStyle = USE_SQL_DATES;
else if (strcasecmp(DBDate, "POSTGRES") == 0)
DateStyle = USE_POSTGRES_DATES;
else if (strcasecmp(DBDate, "GERMAN") == 0)
{
DateStyle = USE_GERMAN_DATES;
EuroDates = TRUE;
}
if (strcasecmp(DBDate, "NONEURO") == 0)
EuroDates = FALSE;
else if (strcasecmp(DBDate, "EURO") == 0)
EuroDates = TRUE;
}
optind = 1; /* reset after postmaster usage */
while ((flag = getopt(argc, argv,
"A:B:bCD:d:Eef:iK:Lm:MNo:P:pQS:st:v:x:FW:"))
!= EOF)
switch (flag)
{
case 'A':
/* ----------------
* enable/disable assert checking.
* ----------------
*/
#ifdef USE_ASSERT_CHECKING
assert_enabled = atoi(optarg);
#else
fprintf(stderr, "Assert checking is not enabled\n");
#endif
break;
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 = true;
break;
case 'D': /* PGDATA directory */
DataDir = optarg;
case 'd': /* debug level */
flagQ = false;
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 = true;
break;
case 'e':
/* --------------------------
* Use european date formats.
* --------------------------
*/
flagEu = true;
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_mergejoin_ = 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);
#else
fprintf(stderr, "Lock debug not compiled in\n");
#endif
break;
case 'L':
/* --------------------
* turn off locking
* --------------------
*/
lockingOff = 1;
break;
case 'm':
/* Multiplexed backends are no longer supported. */
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 = true;
break;
case 'S':
/* ----------------
1997-09-18 16:33:46 +02:00
* S - amount of sort memory to use in 1k bytes
* ----------------
*/
{
int S;
1997-09-18 16:33:46 +02:00
S = atoi(optarg);
if (S >= 4 * BLCKSZ / 1024)
1997-09-18 16:33:46 +02:00
SortMem = S;
}
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 'v':
FrontendProtocol = (ProtocolVersion) atoi(optarg);
break;
case 'W':
/* ----------------
* wait N seconds to allow attach from a debugger
* ----------------
*/
sleep(atoi(optarg));
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();
#ifdef CYR_RECODE
SetCharSet();
#endif
if (FindExec(pg_pathname, argv[0], "postgres") < 0)
elog(FATAL, "%s: could not locate executable, bailing out...",
argv[0]);
if (errs || argc - optind > 1)
{
usage(argv[0]);
proc_exit(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]);
proc_exit(1);
}
if (ShowStats &&
(ShowParserStats || ShowPlannerStats || ShowExecutorStats))
{
fprintf(stderr, "-s can not be used together with -t.\n");
proc_exit(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]);
proc_exit(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("\tDatabaseName = [%s]\n", DBName);
puts("\t----------------\n");
}
/* ----------------
* set process params for ps
* ----------------
*/
if (IsUnderPostmaster)
{
int i;
Assert(real_argc >= 4);
real_argv[1] = userName;
real_argv[2] = DBName;
ps_status = (const char **)&real_argv[3];
*ps_status = "idle";
for (i = 4; i < real_argc; i++)
real_argv[i] = ""; /* blank them */
}
/* we just put a dummy here so we don't have to test everywhere */
else ps_status = malloc(sizeof(char *));
/* ----------------
* initialize portal file descriptors
* ----------------
*/
if (IsUnderPostmaster)
{
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);
whereToSendOutput = Remote;
}
else
whereToSendOutput = Debug;
SetProcessingMode(InitProcessing);
/* initialize */
if (!Quiet)
puts("\tInitPostgres()..");
InitPostgres(DBName);
#ifdef MULTIBYTE
/* set default client encoding */
if (!Quiet)
{
puts("\treset_client_encoding()..");
}
reset_client_encoding();
if (!Quiet)
{
puts("\treset_client_encoding() done.");
}
#endif
/* ----------------
* Set up handler for cancel-request signal, and
* send this backend's cancellation info to the frontend.
* This should not be done until we are sure startup is successful.
* ----------------
*/
pqsignal(SIGINT, QueryCancelHandler);
if (whereToSendOutput == Remote &&
PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2)
{
pq_putnchar("K", 1);
pq_putint((int32) MyProcPid, sizeof(int32));
pq_putint((int32) MyCancelKey, sizeof(int32));
/* Need not flush since ReadyForQuery will do it. */
}
/* ----------------
* 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(ERROR) causes a kill(getpid(), SIGHUP) to occur sending
* us back here.
* ----------------
*/
pqsignal(SIGHUP, handle_warn);
if (sigsetjmp(Warn_restart, 1) != 0)
{
InError = true;
time(&tim);
if (!Quiet)
printf("\tAbortCurrentTransaction() at %s\n", ctime(&tim));
1997-09-18 22:22:58 +02:00
MemSet(parser_input, 0, MAX_PARSE_BUFFER);
AbortCurrentTransaction();
}
InError = false;
/* ----------------
* POSTGRES main processing loop begins here
* ----------------
*/
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface");
puts("$Revision: 1.85 $ $Date: 1998/08/25 21:04:38 $");
}
/* ----------------
* 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_shmem_exit(FlushBufferPool, NULL);
for (;;)
{
/* ----------------
* (0) tell the frontend we're ready for a new query.
* ----------------
*/
ReadyForQuery(whereToSendOutput);
/* ----------------
* (1) read a command.
* ----------------
*/
1997-09-18 22:22:58 +02:00
MemSet(parser_input, 0, MAX_PARSE_BUFFER);
firstchar = ReadCommand(parser_input);
QueryCancel = false;
/* 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();
*ps_status = "idle";
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_exec_query(parser_input);
*ps_status = "idle";
if (ShowStats)
ShowUsage();
}
break;
/* ----------------
* 'X' means that the frontend is closing down the socket
* ----------------
*/
case 'X':
pq_close();
proc_exit(0);
break;
default:
elog(ERROR, "unknown frontend message was received");
}
/* ----------------
* (3) commit the current transaction
*
* Note: if we had an empty input buffer, then we didn't
* call pg_exec_query, 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)
NullCommand(Remote);
}
} /* infinite for-loop */
proc_exit(0);
return 1;
}
#ifndef HAVE_GETRUSAGE
#include "rusagestub.h"
#else /* HAVE_GETRUSAGE */
#include <sys/resource.h>
#endif /* HAVE_GETRUSAGE */
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(); */
}
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);
#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); */
}
#ifdef USE_ASSERT_CHECKING
int
assertEnable(int val)
{
assert_enabled = val;
return val;
}
#ifdef ASSERT_CHECKING_TEST
int
assertTest(int val)
{
Assert(val == 0);
if (assert_enabled) {
/* val != 0 should be trapped by previous Assert */
elog(NOTICE, "Assert test successfull (val = %d)", val);
} else {
elog(NOTICE, "Assert checking is disabled (val = %d)", val);
}
return val;
}
#endif
#endif