summaryrefslogtreecommitdiffstats
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/int8.c15
-rw-r--r--src/backend/utils/adt/jsonpath_exec.c3
-rw-r--r--src/backend/utils/adt/ruleutils.c89
-rw-r--r--src/backend/utils/adt/timestamp.c92
-rw-r--r--src/backend/utils/adt/windowfuncs.c1
-rw-r--r--src/backend/utils/adt/xid8funcs.c30
-rw-r--r--src/backend/utils/fmgr/funcapi.c10
-rw-r--r--src/backend/utils/misc/postgresql.conf.sample6
-rw-r--r--src/backend/utils/misc/ps_status.c35
-rw-r--r--src/backend/utils/mmgr/dsa.c10
-rw-r--r--src/backend/utils/sort/logtape.c6
11 files changed, 204 insertions, 93 deletions
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 98d4323..464b64b 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -833,6 +833,21 @@ int8inc_support(PG_FUNCTION_ARGS)
SupportRequestWFuncMonotonic *req = (SupportRequestWFuncMonotonic *) rawreq;
MonotonicFunction monotonic = MONOTONICFUNC_NONE;
int frameOptions = req->window_clause->frameOptions;
+ WindowFunc *wfunc = req->window_func;
+
+ if (list_length(wfunc->args) == 1)
+ {
+ Node *expr = eval_const_expressions(NULL, linitial(wfunc->args));
+
+ /*
+ * Due to the Node representation of WindowClause runConditions in
+ * version prior to v17, we need to insist that the count arg is
+ * Const to allow safe application of the runCondition
+ * optimization.
+ */
+ if (!IsA(expr, Const))
+ PG_RETURN_POINTER(NULL);
+ }
/* No ORDER BY clause then all rows are peers */
if (req->window_clause->orderClause == NIL)
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index c8368ea..f7edfb3 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -1231,6 +1231,9 @@ executeBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp,
JsonPathBool res;
JsonPathBool res2;
+ /* since this function recurses, it could be driven to stack overflow */
+ check_stack_depth();
+
if (!canHaveNext && jspHasNext(jsp))
elog(ERROR, "boolean jsonpath item cannot have next item");
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index a1c1831..a427771 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -352,8 +352,7 @@ static char *pg_get_partkeydef_worker(Oid relid, int prettyFlags,
bool attrsOnly, bool missing_ok);
static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
int prettyFlags, bool missing_ok);
-static text *pg_get_expr_worker(text *expr, Oid relid, const char *relname,
- int prettyFlags);
+static text *pg_get_expr_worker(text *expr, Oid relid, int prettyFlags);
static int print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args, bool print_defaults);
static void print_function_rettype(StringInfo buf, HeapTuple proctup);
@@ -2630,6 +2629,11 @@ decompile_column_index_array(Datum column_index_array, Oid relId,
* partial indexes, column default expressions, etc. We also support
* Var-free expressions, for which the OID can be InvalidOid.
*
+ * If the OID is nonzero but not actually valid, don't throw an error,
+ * just return NULL. This is a bit questionable, but it's what we've
+ * done historically, and it can help avoid unwanted failures when
+ * examining catalog entries for just-deleted relations.
+ *
* We expect this function to work, or throw a reasonably clean error,
* for any node tree that can appear in a catalog pg_node_tree column.
* Query trees, such as those appearing in pg_rewrite.ev_action, are
@@ -2642,29 +2646,16 @@ pg_get_expr(PG_FUNCTION_ARGS)
{
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1);
+ text *result;
int prettyFlags;
- char *relname;
prettyFlags = PRETTYFLAG_INDENT;
- if (OidIsValid(relid))
- {
- /* Get the name for the relation */
- relname = get_rel_name(relid);
-
- /*
- * If the OID isn't actually valid, don't throw an error, just return
- * NULL. This is a bit questionable, but it's what we've done
- * historically, and it can help avoid unwanted failures when
- * examining catalog entries for just-deleted relations.
- */
- if (relname == NULL)
- PG_RETURN_NULL();
- }
+ result = pg_get_expr_worker(expr, relid, prettyFlags);
+ if (result)
+ PG_RETURN_TEXT_P(result);
else
- relname = NULL;
-
- PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
+ PG_RETURN_NULL();
}
Datum
@@ -2673,33 +2664,27 @@ pg_get_expr_ext(PG_FUNCTION_ARGS)
text *expr = PG_GETARG_TEXT_PP(0);
Oid relid = PG_GETARG_OID(1);
bool pretty = PG_GETARG_BOOL(2);
+ text *result;
int prettyFlags;
- char *relname;
prettyFlags = GET_PRETTY_FLAGS(pretty);
- if (OidIsValid(relid))
- {
- /* Get the name for the relation */
- relname = get_rel_name(relid);
- /* See notes above */
- if (relname == NULL)
- PG_RETURN_NULL();
- }
+ result = pg_get_expr_worker(expr, relid, prettyFlags);
+ if (result)
+ PG_RETURN_TEXT_P(result);
else
- relname = NULL;
-
- PG_RETURN_TEXT_P(pg_get_expr_worker(expr, relid, relname, prettyFlags));
+ PG_RETURN_NULL();
}
static text *
-pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
+pg_get_expr_worker(text *expr, Oid relid, int prettyFlags)
{
Node *node;
Node *tst;
Relids relids;
List *context;
char *exprstr;
+ Relation rel = NULL;
char *str;
/* Convert input pg_node_tree (really TEXT) object to C string */
@@ -2744,9 +2729,19 @@ pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
errmsg("expression contains variables")));
}
- /* Prepare deparse context if needed */
+ /*
+ * Prepare deparse context if needed. If we are deparsing with a relid,
+ * we need to transiently open and lock the rel, to make sure it won't go
+ * away underneath us. (set_relation_column_names would lock it anyway,
+ * so this isn't really introducing any new behavior.)
+ */
if (OidIsValid(relid))
- context = deparse_context_for(relname, relid);
+ {
+ rel = try_relation_open(relid, AccessShareLock);
+ if (rel == NULL)
+ return NULL;
+ context = deparse_context_for(RelationGetRelationName(rel), relid);
+ }
else
context = NIL;
@@ -2754,6 +2749,9 @@ pg_get_expr_worker(text *expr, Oid relid, const char *relname, int prettyFlags)
str = deparse_expression_pretty(node, context, false, false,
prettyFlags, 0);
+ if (rel != NULL)
+ relation_close(rel, AccessShareLock);
+
return string_to_text(str);
}
@@ -5015,8 +5013,11 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
* For a WorkTableScan, locate the parent RecursiveUnion plan node and use
* that as INNER referent.
*
- * For MERGE, make the inner tlist point to the merge source tlist, which
- * is same as the targetlist that the ModifyTable's source plan provides.
+ * For MERGE, pretend the ModifyTable's source plan (its outer plan) is
+ * INNER referent. This is the join from the target relation to the data
+ * source, and all INNER_VAR Vars in other parts of the query refer to its
+ * targetlist.
+ *
* For ON CONFLICT .. UPDATE we just need the inner tlist to point to the
* excluded expression's tlist. (Similar to the SubqueryScan we don't want
* to reuse OUTER, it's used for RETURNING in some modify table cases,
@@ -5031,17 +5032,17 @@ set_deparse_plan(deparse_namespace *dpns, Plan *plan)
dpns->inner_plan = find_recursive_union(dpns,
(WorkTableScan *) plan);
else if (IsA(plan, ModifyTable))
- dpns->inner_plan = plan;
- else
- dpns->inner_plan = innerPlan(plan);
-
- if (IsA(plan, ModifyTable))
{
if (((ModifyTable *) plan)->operation == CMD_MERGE)
- dpns->inner_tlist = dpns->outer_tlist;
+ dpns->inner_plan = outerPlan(plan);
else
- dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
+ dpns->inner_plan = plan;
}
+ else
+ dpns->inner_plan = innerPlan(plan);
+
+ if (IsA(plan, ModifyTable) && ((ModifyTable *) plan)->operation == CMD_INSERT)
+ dpns->inner_tlist = ((ModifyTable *) plan)->exclRelTlist;
else if (dpns->inner_plan)
dpns->inner_tlist = dpns->inner_plan->targetlist;
else
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 27073cb..1544d54 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -2915,7 +2915,10 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
- tm->tm_mon += span->month;
+ if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
if (tm->tm_mon > MONTHS_PER_YEAR)
{
tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
@@ -2967,7 +2970,10 @@ timestamp_pl_interval(PG_FUNCTION_ARGS)
errmsg("timestamp out of range")));
}
- timestamp += span->time;
+ if (pg_add_s64_overflow(timestamp, span->time, &timestamp))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
if (!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
@@ -3029,7 +3035,10 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("timestamp out of range")));
- tm->tm_mon += span->month;
+ if (pg_add_s32_overflow(tm->tm_mon, span->month, &tm->tm_mon))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
if (tm->tm_mon > MONTHS_PER_YEAR)
{
tm->tm_year += (tm->tm_mon - 1) / MONTHS_PER_YEAR;
@@ -3088,7 +3097,10 @@ timestamptz_pl_interval(PG_FUNCTION_ARGS)
errmsg("timestamp out of range")));
}
- timestamp += span->time;
+ if (pg_add_s64_overflow(timestamp, span->time, &timestamp))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
if (!IS_VALID_TIMESTAMP(timestamp))
ereport(ERROR,
@@ -3924,8 +3936,9 @@ timestamp_bin(PG_FUNCTION_ARGS)
Timestamp timestamp = PG_GETARG_TIMESTAMP(1);
Timestamp origin = PG_GETARG_TIMESTAMP(2);
Timestamp result,
- tm_diff,
stride_usecs,
+ tm_diff,
+ tm_modulo,
tm_delta;
if (TIMESTAMP_NOT_FINITE(timestamp))
@@ -3941,24 +3954,40 @@ timestamp_bin(PG_FUNCTION_ARGS)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
- stride_usecs = stride->day * USECS_PER_DAY + stride->time;
+ if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
+ unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
if (stride_usecs <= 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("stride must be greater than zero")));
- tm_diff = timestamp - origin;
- tm_delta = tm_diff - tm_diff % stride_usecs;
+ if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
+ /* These calculations cannot overflow */
+ tm_modulo = tm_diff % stride_usecs;
+ tm_delta = tm_diff - tm_modulo;
+ result = origin + tm_delta;
/*
- * Make sure the returned timestamp is at the start of the bin, even if
- * the origin is in the future.
+ * We want to round towards -infinity, not 0, when tm_diff is negative and
+ * not a multiple of stride_usecs. This adjustment *can* cause overflow,
+ * since the result might now be out of the range origin .. timestamp.
*/
- if (origin > timestamp && stride_usecs > 1)
- tm_delta -= stride_usecs;
-
- result = origin + tm_delta;
+ if (tm_modulo < 0)
+ {
+ if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
+ !IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+ }
PG_RETURN_TIMESTAMP(result);
}
@@ -4109,6 +4138,7 @@ timestamptz_bin(PG_FUNCTION_ARGS)
TimestampTz result,
stride_usecs,
tm_diff,
+ tm_modulo,
tm_delta;
if (TIMESTAMP_NOT_FINITE(timestamp))
@@ -4124,24 +4154,40 @@ timestamptz_bin(PG_FUNCTION_ARGS)
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("timestamps cannot be binned into intervals containing months or years")));
- stride_usecs = stride->day * USECS_PER_DAY + stride->time;
+ if (unlikely(pg_mul_s64_overflow(stride->day, USECS_PER_DAY, &stride_usecs)) ||
+ unlikely(pg_add_s64_overflow(stride_usecs, stride->time, &stride_usecs)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
if (stride_usecs <= 0)
ereport(ERROR,
(errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
errmsg("stride must be greater than zero")));
- tm_diff = timestamp - origin;
- tm_delta = tm_diff - tm_diff % stride_usecs;
+ if (unlikely(pg_sub_s64_overflow(timestamp, origin, &tm_diff)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("interval out of range")));
+
+ /* These calculations cannot overflow */
+ tm_modulo = tm_diff % stride_usecs;
+ tm_delta = tm_diff - tm_modulo;
+ result = origin + tm_delta;
/*
- * Make sure the returned timestamp is at the start of the bin, even if
- * the origin is in the future.
+ * We want to round towards -infinity, not 0, when tm_diff is negative and
+ * not a multiple of stride_usecs. This adjustment *can* cause overflow,
+ * since the result might now be out of the range origin .. timestamp.
*/
- if (origin > timestamp && stride_usecs > 1)
- tm_delta -= stride_usecs;
-
- result = origin + tm_delta;
+ if (tm_modulo < 0)
+ {
+ if (unlikely(pg_sub_s64_overflow(result, stride_usecs, &result)) ||
+ !IS_VALID_TIMESTAMP(result))
+ ereport(ERROR,
+ (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE),
+ errmsg("timestamp out of range")));
+ }
PG_RETURN_TIMESTAMPTZ(result);
}
diff --git a/src/backend/utils/adt/windowfuncs.c b/src/backend/utils/adt/windowfuncs.c
index 596564f..871119e 100644
--- a/src/backend/utils/adt/windowfuncs.c
+++ b/src/backend/utils/adt/windowfuncs.c
@@ -14,6 +14,7 @@
#include "postgres.h"
#include "nodes/supportnodes.h"
+#include "optimizer/optimizer.h"
#include "utils/builtins.h"
#include "windowapi.h"
diff --git a/src/backend/utils/adt/xid8funcs.c b/src/backend/utils/adt/xid8funcs.c
index d8e40b3..3af9eba 100644
--- a/src/backend/utils/adt/xid8funcs.c
+++ b/src/backend/utils/adt/xid8funcs.c
@@ -90,11 +90,12 @@ typedef struct
static bool
TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
{
- uint32 xid_epoch = EpochFromFullTransactionId(fxid);
TransactionId xid = XidFromFullTransactionId(fxid);
uint32 now_epoch;
TransactionId now_epoch_next_xid;
FullTransactionId now_fullxid;
+ TransactionId oldest_xid;
+ FullTransactionId oldest_fxid;
now_fullxid = ReadNextFullTransactionId();
now_epoch_next_xid = XidFromFullTransactionId(now_fullxid);
@@ -127,17 +128,24 @@ TransactionIdInRecentPast(FullTransactionId fxid, TransactionId *extracted_xid)
Assert(LWLockHeldByMe(XactTruncationLock));
/*
- * If the transaction ID has wrapped around, it's definitely too old to
- * determine the commit status. Otherwise, we can compare it to
- * ShmemVariableCache->oldestClogXid to determine whether the relevant
- * CLOG entry is guaranteed to still exist.
+ * If fxid is not older than ShmemVariableCache->oldestClogXid, the
+ * relevant CLOG entry is guaranteed to still exist. Convert
+ * ShmemVariableCache->oldestClogXid into a FullTransactionId to compare
+ * it with fxid. Determine the right epoch knowing that oldest_fxid
+ * shouldn't be more than 2^31 older than now_fullxid.
*/
- if (xid_epoch + 1 < now_epoch
- || (xid_epoch + 1 == now_epoch && xid < now_epoch_next_xid)
- || TransactionIdPrecedes(xid, ShmemVariableCache->oldestClogXid))
- return false;
-
- return true;
+ oldest_xid = ShmemVariableCache->oldestClogXid;
+ Assert(TransactionIdPrecedesOrEquals(oldest_xid, now_epoch_next_xid));
+ if (oldest_xid <= now_epoch_next_xid)
+ {
+ oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch, oldest_xid);
+ }
+ else
+ {
+ Assert(now_epoch > 0);
+ oldest_fxid = FullTransactionIdFromEpochAndXid(now_epoch - 1, oldest_xid);
+ }
+ return !FullTransactionIdPrecedes(fxid, oldest_fxid);
}
/*
diff --git a/src/backend/utils/fmgr/funcapi.c b/src/backend/utils/fmgr/funcapi.c
index 31f6662..89c7ed9 100644
--- a/src/backend/utils/fmgr/funcapi.c
+++ b/src/backend/utils/fmgr/funcapi.c
@@ -296,6 +296,13 @@ get_call_result_type(FunctionCallInfo fcinfo,
/*
* get_expr_result_type
* As above, but work from a calling expression node tree
+ *
+ * Beware of using this on the funcexpr of a RTE that has a coldeflist.
+ * The correct conclusion in such cases is always that the function returns
+ * RECORD with the columns defined by the coldeflist fields (funccolnames etc).
+ * If it does not, it's the executor's responsibility to catch the discrepancy
+ * at runtime; but code processing the query in advance of that point might
+ * come to inconsistent conclusions if it checks the actual expression.
*/
TypeFuncClass
get_expr_result_type(Node *expr,
@@ -546,7 +553,8 @@ internal_get_result_type(Oid funcid,
* if noError is true, else throws error.
*
* This is a simpler version of get_expr_result_type() for use when the caller
- * is only interested in determinate rowtype results.
+ * is only interested in determinate rowtype results. As with that function,
+ * beware of using this on the funcexpr of a RTE that has a coldeflist.
*/
TupleDesc
get_expr_result_tupdesc(Node *expr, bool noError)
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index f92ff4c..7bf891a 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -187,9 +187,9 @@
#effective_io_concurrency = 1 # 1-1000; 0 disables prefetching
#maintenance_io_concurrency = 10 # 1-1000; 0 disables prefetching
#max_worker_processes = 8 # (change requires restart)
-#max_parallel_workers_per_gather = 2 # taken from max_parallel_workers
-#max_parallel_maintenance_workers = 2 # taken from max_parallel_workers
-#max_parallel_workers = 8 # maximum number of max_worker_processes that
+#max_parallel_workers_per_gather = 2 # limited by max_parallel_workers
+#max_parallel_maintenance_workers = 2 # limited by max_parallel_workers
+#max_parallel_workers = 8 # number of max_worker_processes that
# can be used in parallel operations
#parallel_leader_participation = on
#old_snapshot_threshold = -1 # 1min-60d; -1 disables; 0 is immediate
diff --git a/src/backend/utils/misc/ps_status.c b/src/backend/utils/misc/ps_status.c
index ec314c0..d98993b 100644
--- a/src/backend/utils/misc/ps_status.c
+++ b/src/backend/utils/misc/ps_status.c
@@ -122,7 +122,8 @@ static char **save_argv;
* (The original argv[] will not be overwritten by this routine, but may be
* overwritten during init_ps_display. Also, the physical location of the
* environment strings may be moved, so this should be called before any code
- * that might try to hang onto a getenv() result.)
+ * that might try to hang onto a getenv() result. But see hack for musl
+ * within.)
*
* Note that in case of failure this cannot call elog() as that is not
* initialized yet. We rely on write_stderr() instead.
@@ -137,7 +138,7 @@ save_ps_display_args(int argc, char **argv)
/*
* If we're going to overwrite the argv area, count the available space.
- * Also move the environment to make additional room.
+ * Also move the environment strings to make additional room.
*/
{
char *end_of_area = NULL;
@@ -166,7 +167,33 @@ save_ps_display_args(int argc, char **argv)
for (i = 0; environ[i] != NULL; i++)
{
if (end_of_area + 1 == environ[i])
- end_of_area = environ[i] + strlen(environ[i]);
+ {
+ /*
+ * The musl dynamic linker keeps a static pointer to the
+ * initial value of LD_LIBRARY_PATH, if that is defined in the
+ * process's environment. Therefore, we must not overwrite the
+ * value of that setting and thus cannot advance end_of_area
+ * beyond it. Musl does not define any identifying compiler
+ * symbol, so we have to do this unless we see a symbol
+ * identifying a Linux libc we know is safe.
+ */
+#if defined(__linux__) && (!defined(__GLIBC__) && !defined(__UCLIBC__))
+ if (strncmp(environ[i], "LD_LIBRARY_PATH=", 16) == 0)
+ {
+ /*
+ * We can overwrite the name, but stop at the equals sign.
+ * Future loop iterations will not find any more
+ * contiguous space, but we don't break early because we
+ * need to count the total number of environ[] entries.
+ */
+ end_of_area = environ[i] + 15;
+ }
+ else
+#endif
+ {
+ end_of_area = environ[i] + strlen(environ[i]);
+ }
+ }
}
ps_buffer = argv[0];
@@ -201,7 +228,7 @@ save_ps_display_args(int argc, char **argv)
* If we're going to change the original argv[] then make a copy for
* argument parsing purposes.
*
- * (NB: do NOT think to remove the copying of argv[], even though
+ * NB: do NOT think to remove the copying of argv[], even though
* postmaster.c finishes looking at argv[] long before we ever consider
* changing the ps display. On some platforms, getopt() keeps pointers
* into the argv array, and will get horribly confused when it is
diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c
index 7d0686b..c3c69bd 100644
--- a/src/backend/utils/mmgr/dsa.c
+++ b/src/backend/utils/mmgr/dsa.c
@@ -1093,9 +1093,13 @@ dsa_dump(dsa_area *area)
{
dsa_segment_index segment_index;
- fprintf(stderr,
- " segment bin %zu (at least %d contiguous pages free):\n",
- i, 1 << (i - 1));
+ if (i == 0)
+ fprintf(stderr,
+ " segment bin %zu (no contiguous free pages):\n", i);
+ else
+ fprintf(stderr,
+ " segment bin %zu (at least %d contiguous pages free):\n",
+ i, 1 << (i - 1));
segment_index = area->control->segment_bins[i];
while (segment_index != DSA_SEGMENT_INDEX_NONE)
{
diff --git a/src/backend/utils/sort/logtape.c b/src/backend/utils/sort/logtape.c
index 31db75d..fb0d395 100644
--- a/src/backend/utils/sort/logtape.c
+++ b/src/backend/utils/sort/logtape.c
@@ -1181,10 +1181,8 @@ LogicalTapeTell(LogicalTape *lt, long *blocknum, int *offset)
}
/*
- * Obtain total disk space currently used by a LogicalTapeSet, in blocks.
- *
- * This should not be called while there are open write buffers; otherwise it
- * may not account for buffered data.
+ * Obtain total disk space currently used by a LogicalTapeSet, in blocks. Does
+ * not account for open write buffer, if any.
*/
long
LogicalTapeSetBlocks(LogicalTapeSet *lts)