📄 postgres.c
字号:
/*------------------------------------------------------------------------- * * postgres.c * POSTGRES C Backend Interface * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /usr/local/cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.119 1999/07/02 18:09:27 momjian Exp $ * * NOTES * this is the "main" module of the postgres backend and * hence the main module of the "traffic cop". * *------------------------------------------------------------------------- */#include <unistd.h>#include <stdio.h>#include <string.h>#include <signal.h>#include <time.h>#include <sys/time.h>#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 */#include <sys/socket.h>#endif#include <errno.h>#if HAVE_SYS_SELECT_H#include <sys/select.h>#endif /* aix */#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#ifdef __CYGWIN32__#include <getopt.h>#endif#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/pqformat.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"#include "utils/ps_status.h"#include "utils/temprel.h"#include "nodes/parsenodes.h"#include "../backend/parser/parse.h"#ifdef NOT_USED#include "nodes/relation.h"#endif#ifdef NOT_USED#include "optimizer/xfunc.h"#endif#ifdef NOT_USED#include "nodes/plannodes.h"#endif#ifdef NOT_USED#include "nodes/memnodes.h"#endif#include "utils/trace.h"#ifdef MULTIBYTE#include "mb/pg_wchar.h"#endif/* * Trace flags, see backend/utils/misc/trace.c */#define Verbose pg_options[TRACE_VERBOSE]#define DebugPrintQuery pg_options[TRACE_QUERY]#define DebugPrintPlan pg_options[TRACE_PLAN]#define DebugPrintParse pg_options[TRACE_PARSE]#define DebugPrintRewrittenParsetree \ pg_options[TRACE_REWRITTEN]#define DebugPPrintPlan pg_options[TRACE_PRETTY_PLAN]#define DebugPPrintParse pg_options[TRACE_PRETTY_PARSE]#define DebugPPrintRewrittenParsetree \ pg_options[TRACE_PRETTY_REWRITTEN]#define ShowParserStats pg_options[TRACE_PARSERSTATS]#define ShowPlannerStats pg_options[TRACE_PLANNERSTATS]#define ShowExecutorStats pg_options[TRACE_EXECUTORSTATS]#ifdef LOCK_MGR_DEBUG#define LockDebug pg_options[TRACE_LOCKS]#endif#define DeadlockCheckTimer pg_options[OPT_DEADLOCKTIMEOUT]#define HostnameLookup pg_options[OPT_HOSTLOOKUP]#define ShowPortNumber pg_options[OPT_SHOWPORTNUMBER]/* ---------------- * global variables * ---------------- *//*static bool EnableRewrite = true; , never changes why have it*/CommandDest whereToSendOutput;/* Define status buffer needed by PS_SET_STATUS */PS_DEFINE_BUFFER;extern int lockingOff;extern int NBuffers;int dontExecute = 0;static int ShowStats;static bool IsEmptyQuery = false;char relname[80]; /* current relation name *//* note: these declarations had better match tcopprot.h */DLLIMPORT sigjmp_buf Warn_restart;bool InError;extern int NBuffers;static int EchoQuery = 0; /* default don't echo */time_t tim;char pg_pathname[256];FILE *StatFp;/* ---------------- * people who want to use EOF should #define DONTUSENEWLINE in * tcop/tcopdebug.h * ---------------- */#ifndef TCOP_DONTUSENEWLINEint UseNewLine = 1; /* Use newlines query delimiters (the * default) */#elseint UseNewLine = 0; /* Use EOF as query delimiters */#endif /* TCOP_DONTUSENEWLINE *//*** 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);static void pg_exec_query(char *query_string);/* ---------------------------------------------------------------- * 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 charInteractiveBackend(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("backend> "); fflush(stdout); 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 (Verbose) 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: %s\n", inBuf); fflush(stdout); 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 charSocketBackend(char *inBuf){ char qtype; char result = '\0'; /* ---------------- * get input from the frontend * ---------------- */ qtype = '?'; if (pq_getbytes(&qtype, 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", 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 charReadCommand(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 */ List **queryListP, /* returned pointer to the parse * trees */ CommandDest dest, /* where results should go */ bool aclOverride){ List *querytree_list = NIL; List *plan_list = NIL; List *querytree_list_item; Query *querytree; Plan *plan; List *new_list; List *rewritten; if (DebugPrintQuery) { if (DebugPrintQuery > 3) { /* Print the query string as is if query debug level > 3 */ TPRINTF(TRACE_QUERY, "query: %s", query_string); } else { /* Print condensed query string to fit in one log line */ char buff[MAX_QUERY_SIZE + 1]; char c, *s, *d; int n, is_space = 1; for (s = query_string, d = buff, n = 0; (c = *s) && (n < MAX_QUERY_SIZE); s++) { switch (c) { case '\r': case '\n': case '\t': c = ' '; /* fall through */ case ' ': if (is_space) continue; is_space = 1; break; default: is_space = 0; break; } *d++ = c; n++; } *d = '\0'; TPRINTF(TRACE_QUERY, "query: %s", buff); } } /* ---------------- * (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(); } /* ---------------- * (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(querytree_list_item, querytree_list) { querytree = (Query *) lfirst(querytree_list_item); if (DebugPrintParse || DebugPPrintParse) { if (DebugPPrintParse) { TPRINTF(TRACE_PRETTY_PARSE, "parser outputs:"); nodeDisplay(querytree); } else { TPRINTF(TRACE_PARSE, "parser outputs:"); printf("\n%s\n\n", nodeToString(querytree)); } } 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 */ rewritten = QueryRewrite(querytree); new_list = nconc(new_list, rewritten); } } querytree_list = new_list; /* * Override ACL checking if requested */ if (aclOverride) { foreach(querytree_list_item, querytree_list) { List *l; querytree = (Query *) lfirst(querytree_list_item); if (querytree->commandType == CMD_UTILITY) continue; foreach(l, querytree->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); rte->skipAcl = TRUE; } } } if (DebugPrintRewrittenParsetree || DebugPPrintRewrittenParsetree) { if (DebugPPrintRewrittenParsetree) { TPRINTF(TRACE_PRETTY_REWRITTEN, "after rewriting:"); foreach(querytree_list_item, querytree_list) { querytree = (Query *) lfirst(querytree_list_item); nodeDisplay(querytree); printf("\n"); } } else { TPRINTF(TRACE_REWRITTEN, "after rewriting:"); foreach(querytree_list_item, querytree_list) { querytree = (Query *) lfirst(querytree_list_item); printf("\n%s\n\n", nodeToString(querytree)); } } } foreach(querytree_list_item, querytree_list) { querytree = (Query *) lfirst(querytree_list_item); /* * 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"); if (queryListP) *queryListP = NIL; return NIL; } 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 || DebugPPrintPlan) { if (DebugPPrintPlan) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -