postgres.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,551 行 · 第 1/5 页
C
2,551 行
/*------------------------------------------------------------------------- * * postgres.c * POSTGRES C Backend Interface * * Portions Copyright (c) 1996-2003, 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.375.2.2 2004/09/26 00:26:53 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and * hence the main module of the "traffic cop". * *------------------------------------------------------------------------- */#include "postgres.h"#include <unistd.h>#include <signal.h>#include <time.h>#include <sys/time.h>#include <fcntl.h>#include <sys/socket.h>#include <errno.h>#if HAVE_SYS_SELECT_H#include <sys/select.h>#endif#ifdef HAVE_GETOPT_H#include <getopt.h>#endif#include "access/printtup.h"#include "access/xlog.h"#include "catalog/pg_type.h"#include "commands/async.h"#include "commands/prepare.h"#include "commands/trigger.h"#include "libpq/libpq.h"#include "libpq/pqformat.h"#include "libpq/pqsignal.h"#include "miscadmin.h"#include "nodes/print.h"#include "optimizer/cost.h"#include "optimizer/planner.h"#include "parser/analyze.h"#include "parser/parser.h"#include "rewrite/rewriteHandler.h"#include "storage/freespace.h"#include "storage/ipc.h"#include "storage/pg_shmem.h"#include "storage/proc.h"#include "tcop/fastpath.h"#include "tcop/pquery.h"#include "tcop/tcopprot.h"#include "tcop/utility.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/memutils.h"#include "utils/ps_status.h"#include "mb/pg_wchar.h"#include "pgstat.h"extern int optind;extern char *optarg;/* ---------------- * global variables * ---------------- */const char *debug_query_string; /* for pgmonitor and * log_min_error_statement *//* Note: whereToSendOutput is initialized for the bootstrap/standalone case */CommandDest whereToSendOutput = Debug;/* note: these declarations had better match tcopprot.h */sigjmp_buf Warn_restart;bool Warn_restart_ready = false;bool InError = false;/* * Flags for expensive function optimization -- JMH 3/9/92 */int XfuncMode = 0;/* ---------------- * private variables * ---------------- *//* * 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;/* * Flag to keep track of whether we have started a transaction. * For extended query protocol this has to be remembered across messages. */static bool xact_started = false;/* * Flags to implement skip-till-Sync-after-error behavior for messages of * the extended query protocol. */static bool doing_extended_query_message = false;static bool ignore_till_sync = false;/* * If an unnamed prepared statement exists, it's stored here. * We keep it separate from the hashtable kept by commands/prepare.c * in order to reduce overhead for short-lived queries. */static MemoryContext unnamed_stmt_context = NULL;static PreparedStatement *unnamed_stmt_pstmt = NULL;static bool EchoQuery = false; /* default don't echo *//* * people who want to use EOF should #define DONTUSENEWLINE in * tcop/tcopdebug.h */#ifndef TCOP_DONTUSENEWLINEstatic int UseNewLine = 1; /* Use newlines query delimiters (the * default) */#elsestatic int UseNewLine = 0; /* Use EOF as query delimiters */#endif /* TCOP_DONTUSENEWLINE *//* ---------------------------------------------------------------- * 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(void);static void SigHupHandler(SIGNAL_ARGS);static void FloatExceptionHandler(SIGNAL_ARGS);/* ---------------------------------------------------------------- * routines to obtain user input * ---------------------------------------------------------------- *//* ---------------- * InteractiveBackend() is called for user interactive connections * * the string entered by the user is placed in its parameter inBuf, * and we act like a Q message was received. * * EOF is returned if end-of-file input is seen; time to shut down. * ---------------- */static intInteractiveBackend(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'; inBuf->cursor = 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; } /* Add '\0' to make it look the same as message case. */ appendStringInfoChar(inBuf, (char) '\0'); /* * if the query echo flag was given, print the query.. */ if (EchoQuery) printf("statement: %s\n", inBuf->data); fflush(stdout); return 'Q';}/* ---------------- * SocketBackend() Is called for frontend-backend connections * * Returns the message type code, and loads message body data into inBuf. * * EOF is returned if the connection is lost. * ---------------- */static intSocketBackend(StringInfo inBuf){ int qtype; /* * Get message type code from the frontend. */ qtype = pq_getbyte(); if (qtype == EOF) /* frontend disconnected */ { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unexpected EOF on client connection"))); return qtype; } /* * Validate message type code before trying to read body; if we have * lost sync, better to say "command unknown" than to run out of * memory because we used garbage as a length word. * * This also gives us a place to set the doing_extended_query_message * flag as soon as possible. */ switch (qtype) { case 'Q': /* simple query */ doing_extended_query_message = false; if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) { /* old style without length word; convert */ if (pq_getstring(inBuf)) { ereport(COMMERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("unexpected EOF on client connection"))); return EOF; } } break; case 'F': /* fastpath function call */ /* we let fastpath.c cope with old-style input of this */ doing_extended_query_message = false; break; case 'X': /* terminate */ doing_extended_query_message = false; ignore_till_sync = false; break; case 'B': /* bind */ case 'C': /* close */ case 'D': /* describe */ case 'E': /* execute */ case 'H': /* flush */ case 'P': /* parse */ doing_extended_query_message = true; /* these are only legal in protocol 3 */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid frontend message type %d", qtype))); break; case 'S': /* sync */ /* stop any active skip-till-Sync */ ignore_till_sync = false; /* mark not-extended, so that a new error doesn't begin skip */ doing_extended_query_message = false; /* only legal in protocol 3 */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid frontend message type %d", qtype))); break; case 'd': /* copy data */ case 'c': /* copy done */ case 'f': /* copy fail */ doing_extended_query_message = false; /* these are only legal in protocol 3 */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid frontend message type %d", qtype))); break; default: /* * Otherwise we got garbage from the frontend. We treat this * as fatal because we have probably lost message boundary * sync, and there's no good way to recover. */ ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid frontend message type %d", qtype))); break; } /* * In protocol version 3, all frontend messages have a length word * next after the type code; we can read the message contents * independently of the type. */ if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3) { if (pq_getmessage(inBuf, 0)) return EOF; /* suitable message already logged */ } return qtype;}/* ---------------- * ReadCommand reads a command from either the frontend or * standard input, places it in inBuf, and returns the * message type code (first byte of the message). * EOF is returned if end of file. * ---------------- */static intReadCommand(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 *pg_parse_and_rewrite(const char *query_string, /* string to execute */ Oid *paramTypes, /* parameter types */ int numParams) /* number of parameters */{ List *raw_parsetree_list; List *querytree_list; List *list_item; /* * (1) parse the request string into a list of raw parse trees. */ raw_parsetree_list = pg_parse_query(query_string); /* * (2) Do parse analysis and rule rewrite. */ querytree_list = NIL; foreach(list_item, raw_parsetree_list) { Node *parsetree = (Node *) lfirst(list_item); querytree_list = nconc(querytree_list, pg_analyze_and_rewrite(parsetree, paramTypes, numParams)); } 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(const char *query_string){ List *raw_parsetree_list; if (log_statement) ereport(LOG, (errmsg("statement: %s", query_string))); if (log_parser_stats) ResetUsage(); raw_parsetree_list = raw_parser(query_string); if (log_parser_stats) ShowUsage("PARSER STATISTICS"); return raw_parsetree_list;}/* * Given a raw parsetree (gram.y output), and optionally information about * types of parameter symbols ($n), 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, Oid *paramTypes, int numParams){ List *querytree_list; /* * (1) Perform parse analysis. */ if (log_parser_stats) ResetUsage(); querytree_list = parse_analyze(parsetree, paramTypes, numParams); if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); /* * (2) Rewrite the queries, as necessary */ querytree_list = pg_rewrite_queries(querytree_list); return querytree_list;}/* * Perform rewriting of a list of queries produced by parse analysis.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?