diff options
author | Pavan Deolasee | 2016-10-27 15:02:55 +0000 |
---|---|---|
committer | Pavan Deolasee | 2016-10-27 15:02:55 +0000 |
commit | c52792488cd87e67e62ec61f5b56f461900353b4 (patch) | |
tree | 02b4a719f979659de8f73fce6c1ca65cef2e323f /src/backend/tcop/postgres.c | |
parent | 891e6be57e5580b54a9df9fd42cb9bd10d0e7b21 (diff) | |
parent | b5bce6c1ec6061c8a4f730d927e162db7e2ce365 (diff) |
Merge commit 'b5bce6c1ec6061c8a4f730d927e162db7e2ce365'
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 221 |
1 files changed, 135 insertions, 86 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 31283cc689..95cf984772 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4,7 +4,7 @@ * POSTGRES C Backend Interface * * Portions Copyright (c) 2012-2014, TransLattice, Inc. - * Portions Copyright (c) 1996-2015, PostgreSQL Global Development Group + * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 2010-2012 Postgres-XC Development Group * @@ -176,18 +176,8 @@ static CachedPlanSource *unnamed_stmt_psrc = NULL; /* assorted command-line switches */ static const char *userDoption = NULL; /* -D switch */ - static bool EchoQuery = false; /* -E switch */ - -/* - * people who want to use EOF should #define DONTUSENEWLINE in - * tcop/tcopdebug.h - */ -#ifndef TCOP_DONTUSENEWLINE -static int UseNewLine = 1; /* Use newlines query delimiters (the default) */ -#else -static int UseNewLine = 0; /* Use EOF as query delimiters */ -#endif /* TCOP_DONTUSENEWLINE */ +static bool UseSemiNewlineNewline = false; /* -j switch */ /* whether or not, and why, we were canceled by conflict with recovery */ static bool RecoveryConflictPending = false; @@ -255,8 +245,6 @@ 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 @@ -266,55 +254,56 @@ InteractiveBackend(StringInfo inBuf) resetStringInfo(inBuf); - if (UseNewLine) + /* + * Read characters until EOF or the appropriate delimiter is seen. + */ + while ((c = interactive_getc()) != EOF) { - /* - * if we are using \n as a delimiter, then read characters until the - * \n. - */ - while ((c = interactive_getc()) != EOF) + if (c == '\n') { - if (c == '\n') + if (UseSemiNewlineNewline) { - if (backslashSeen) + /* + * In -j mode, semicolon followed by two newlines ends the + * command; otherwise treat newline as regular character. + */ + if (inBuf->len > 1 && + inBuf->data[inBuf->len - 1] == '\n' && + inBuf->data[inBuf->len - 2] == ';') + { + /* might as well drop the second newline */ + break; + } + } + else + { + /* + * In plain mode, newline ends the command unless preceded by + * backslash. + */ + if (inBuf->len > 0 && + inBuf->data[inBuf->len - 1] == '\\') { /* discard backslash from inBuf */ inBuf->data[--inBuf->len] = '\0'; - backslashSeen = false; + /* discard newline too */ continue; } else { - /* keep the newline character */ + /* keep the newline character, but end the command */ 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 = interactive_getc()) != EOF) - appendStringInfoChar(inBuf, (char) c); - - /* No input before EOF signal means time to quit. */ - if (inBuf->len == 0) - end = true; + /* Not newline, or newline treated as regular character */ + appendStringInfoChar(inBuf, (char) c); } - if (end) + /* No input before EOF signal means time to quit. */ + if (c == EOF && inBuf->len == 0) return EOF; /* @@ -1249,7 +1238,8 @@ exec_simple_query(const char *query_string) querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); - plantree_list = pg_plan_queries(querytree_list, 0, NULL); + plantree_list = pg_plan_queries(querytree_list, + CURSOR_OPT_PARALLEL_OK, NULL); /* Done with the snapshot used for parsing/planning */ if (snapshot_set) @@ -1673,7 +1663,7 @@ exec_parse_message(const char *query_string, /* string to execute */ numParams, NULL, NULL, - 0, /* default cursor options */ + CURSOR_OPT_PARALLEL_OK, /* allow parallel mode */ true); /* fixed result */ /* If we got a cancel signal during analysis, quit */ @@ -2058,6 +2048,7 @@ exec_bind_message(StringInfo input_message) params->parserSetup = NULL; params->parserSetupArg = NULL; params->numParams = numParams; + params->paramMask = NULL; for (paramno = 0; paramno < numParams; paramno++) { @@ -3267,9 +3258,7 @@ RecoveryConflictInterrupt(ProcSignalReason reason) /* * Set the process latch. This function essentially emulates signal * handlers like die() and StatementCancelHandler() and it seems prudent - * to behave similarly as they do. Alternatively all plain backend code - * waiting on that latch, expecting to get interrupted by query cancels et - * al., would also need to set set_latch_on_sigusr1. + * to behave similarly as they do. */ SetLatch(MyLatch); @@ -3363,6 +3352,9 @@ ProcessInterrupts(void) if (QueryCancelPending) { + bool lock_timeout_occurred; + bool stmt_timeout_occurred; + /* * Don't allow query cancel interrupts while reading input from the * client, because we might lose sync in the FE/BE protocol. (Die @@ -3383,17 +3375,29 @@ ProcessInterrupts(void) /* * If LOCK_TIMEOUT and STATEMENT_TIMEOUT indicators are both set, we - * prefer to report the former; but be sure to clear both. + * need to clear both, so always fetch both. + */ + lock_timeout_occurred = get_timeout_indicator(LOCK_TIMEOUT, true); + stmt_timeout_occurred = get_timeout_indicator(STATEMENT_TIMEOUT, true); + + /* + * If both were set, we want to report whichever timeout completed + * earlier; this ensures consistent behavior if the machine is slow + * enough that the second timeout triggers before we get here. A tie + * is arbitrarily broken in favor of reporting a lock timeout. */ - if (get_timeout_indicator(LOCK_TIMEOUT, true)) + if (lock_timeout_occurred && stmt_timeout_occurred && + get_timeout_finish_time(STATEMENT_TIMEOUT) < get_timeout_finish_time(LOCK_TIMEOUT)) + lock_timeout_occurred = false; /* report stmt timeout */ + + if (lock_timeout_occurred) { - (void) get_timeout_indicator(STATEMENT_TIMEOUT, true); LockErrorCleanup(); ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("canceling statement due to lock timeout"))); } - if (get_timeout_indicator(STATEMENT_TIMEOUT, true)) + if (stmt_timeout_occurred) { LockErrorCleanup(); ereport(ERROR, @@ -3432,6 +3436,18 @@ ProcessInterrupts(void) } } + if (IdleInTransactionSessionTimeoutPending) + { + /* Has the timeout setting changed since last we looked? */ + if (IdleInTransactionSessionTimeout > 0) + ereport(FATAL, + (errcode(ERRCODE_IDLE_IN_TRANSACTION_SESSION_TIMEOUT), + errmsg("terminating connection due to idle-in-transaction timeout"))); + else + IdleInTransactionSessionTimeoutPending = false; + + } + if (ParallelMessagePending) HandleParallelMessages(); @@ -3443,33 +3459,35 @@ ProcessInterrupts(void) /* * IA64-specific code to fetch the AR.BSP register for stack depth checks. * - * We currently support gcc, icc, and HP-UX inline assembly here. + * We currently support gcc, icc, and HP-UX's native compiler here. + * + * Note: while icc accepts gcc asm blocks on x86[_64], this is not true on + * ia64 (at least not in icc versions before 12.x). So we have to carry a + * separate implementation for it. */ #if defined(__ia64__) || defined(__ia64) -#if defined(__hpux) && !defined(__GNUC__) && !defined __INTEL_COMPILER +#if defined(__hpux) && !defined(__GNUC__) && !defined(__INTEL_COMPILER) +/* Assume it's HP-UX native compiler */ #include <ia64/sys/inline.h> #define ia64_get_bsp() ((char *) (_Asm_mov_from_ar(_AREG_BSP, _NO_FENCE))) -#else - -#ifdef __INTEL_COMPILER +#elif defined(__INTEL_COMPILER) +/* icc */ #include <asm/ia64regs.h> -#endif - +#define ia64_get_bsp() ((char *) __getReg(_IA64_REG_AR_BSP)) +#else +/* gcc */ static __inline__ char * ia64_get_bsp(void) { char *ret; -#ifndef __INTEL_COMPILER /* the ;; is a "stop", seems to be required before fetching BSP */ __asm__ __volatile__( ";;\n" " mov %0=ar.bsp \n" : "=r"(ret)); -#else - ret = (char *) __getReg(_IA64_REG_AR_BSP); -#endif + return ret; } #endif @@ -3524,16 +3542,33 @@ restore_stack_base(pg_stack_base_t base) } /* - * check_stack_depth: check for excessively deep recursion + * check_stack_depth/stack_is_too_deep: check for excessively deep recursion * * This should be called someplace in any recursive routine that might possibly * recurse deep enough to overflow the stack. Most Unixen treat stack * overflow as an unrecoverable SIGSEGV, so we want to error out ourselves * before hitting the hardware limit. + * + * check_stack_depth() just throws an error summarily. stack_is_too_deep() + * can be used by code that wants to handle the error condition itself. */ void check_stack_depth(void) { + if (stack_is_too_deep()) + { + ereport(ERROR, + (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), + errmsg("stack depth limit exceeded"), + errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), " + "after ensuring the platform's stack depth limit is adequate.", + max_stack_depth))); + } +} + +bool +stack_is_too_deep(void) +{ char stack_top_loc; long stack_depth; @@ -3558,14 +3593,7 @@ check_stack_depth(void) */ if (stack_depth > max_stack_depth_bytes && stack_base_ptr != NULL) - { - ereport(ERROR, - (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), - errmsg("stack depth limit exceeded"), - errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), " - "after ensuring the platform's stack depth limit is adequate.", - max_stack_depth))); - } + return true; /* * On IA64 there is a separate "register" stack that requires its own @@ -3580,15 +3608,10 @@ check_stack_depth(void) if (stack_depth > max_stack_depth_bytes && register_stack_base_ptr != NULL) - { - ereport(ERROR, - (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), - errmsg("stack depth limit exceeded"), - errhint("Increase the configuration parameter \"max_stack_depth\" (currently %dkB), " - "after ensuring the platform's stack depth limit is adequate.", - max_stack_depth))); - } + return true; #endif /* IA64 */ + + return false; } /* GUC check hook for max_stack_depth */ @@ -3836,7 +3859,7 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, case 'j': if (secure) - UseNewLine = 0; + UseSemiNewlineNewline = true; break; case 'k': @@ -4052,6 +4075,7 @@ PostgresMain(int argc, char *argv[], StringInfoData input_message; sigjmp_buf local_sigjmp_buf; volatile bool send_ready_for_query = true; + bool disable_idle_in_transaction_timeout = false; #ifdef PGXC /* PGXC_DATANODE */ /* Snapshot info */ @@ -4483,7 +4507,7 @@ PostgresMain(int argc, char *argv[], if (pq_is_reading_msg()) ereport(FATAL, (errcode(ERRCODE_PROTOCOL_VIOLATION), - errmsg("terminating connection because protocol sync was lost"))); + errmsg("terminating connection because protocol synchronization was lost"))); /* Now we can allow interrupts again */ RESUME_INTERRUPTS(); @@ -4534,11 +4558,27 @@ PostgresMain(int argc, char *argv[], { set_ps_display("idle in transaction (aborted)", false); pgstat_report_activity(STATE_IDLEINTRANSACTION_ABORTED, NULL); + + /* Start the idle-in-transaction timer */ + if (IdleInTransactionSessionTimeout > 0) + { + disable_idle_in_transaction_timeout = true; + enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, + IdleInTransactionSessionTimeout); + } } else if (IsTransactionOrTransactionBlock()) { set_ps_display("idle in transaction", false); pgstat_report_activity(STATE_IDLEINTRANSACTION, NULL); + + /* Start the idle-in-transaction timer */ + if (IdleInTransactionSessionTimeout > 0) + { + disable_idle_in_transaction_timeout = true; + enable_timeout_after(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, + IdleInTransactionSessionTimeout); + } } else { @@ -4598,7 +4638,16 @@ PostgresMain(int argc, char *argv[], DoingCommandRead = false; /* - * (5) check for any other interesting events that happened while we + * (5) turn off the idle-in-transaction timeout + */ + if (disable_idle_in_transaction_timeout) + { + disable_timeout(IDLE_IN_TRANSACTION_SESSION_TIMEOUT, false); + disable_idle_in_transaction_timeout = false; + } + + /* + * (6) check for any other interesting events that happened while we * slept. */ if (got_SIGHUP) @@ -4608,7 +4657,7 @@ PostgresMain(int argc, char *argv[], } /* - * (6) process the command. But ignore it if we're skipping till + * (7) process the command. But ignore it if we're skipping till * Sync. */ if (ignore_till_sync && firstchar != EOF) |