On Wed, Aug 24, 2022 at 10:47:31PM +1200, David Rowley wrote: > On Wed, 24 Aug 2022 at 14:39, Justin Pryzby <pry...@telsasoft.com> wrote: > > Attached are half of the remainder of what I've written, ready for review. > > Thanks for the patches.
> 4. "Repurpose" (variables have the same purpose and may as well use > the same variable) > Would you be able to write a patch for #4. The first of the patches that I sent yesterday was all about "repurposed" vars from outer scope (lc, l, isnull, save_errno), and was 70% of your list of vars to repurpose. Here, I've included the rest of your list. Plus another patch for vars which I'd already written patches to repurpose, but which aren't classified as "repurpose" on your list. For subselect.c, you could remove some more "lc" vars and re-use the "l" var for consistency (but I suppose you won't want that). -- Justin
diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 87b243e0d4b..a090cada400 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -3017,46 +3017,45 @@ XLogFileInitInternal(XLogSegNo logsegno, TimeLineID logtli, } pgstat_report_wait_end(); if (save_errno) { /* * If we fail to make the file, delete it to release disk space */ unlink(tmppath); close(fd); errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not write to file \"%s\": %m", tmppath))); } pgstat_report_wait_start(WAIT_EVENT_WAL_INIT_SYNC); if (pg_fsync(fd) != 0) { - int save_errno = errno; - + save_errno = errno; close(fd); errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not fsync file \"%s\": %m", tmppath))); } pgstat_report_wait_end(); if (close(fd) != 0) ereport(ERROR, (errcode_for_file_access(), errmsg("could not close file \"%s\": %m", tmppath))); /* * Now move the segment into place with its final name. Cope with * possibility that someone else has created the file while we were * filling ours: if so, use ours to pre-create a future log segment. */ installed_segno = logsegno; /* * XXX: What should we use as max_segno? We used to use XLOGfileslop when diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 9be04c8a1e7..dacc989d855 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -16777,45 +16777,44 @@ PreCommit_on_commit_actions(void) oids_to_truncate = lappend_oid(oids_to_truncate, oc->relid); break; case ONCOMMIT_DROP: oids_to_drop = lappend_oid(oids_to_drop, oc->relid); break; } } /* * Truncate relations before dropping so that all dependencies between * relations are removed after they are worked on. Doing it like this * might be a waste as it is possible that a relation being truncated will * be dropped anyway due to its parent being dropped, but this makes the * code more robust because of not having to re-check that the relation * exists at truncation time. */ if (oids_to_truncate != NIL) heap_truncate(oids_to_truncate); if (oids_to_drop != NIL) { ObjectAddresses *targetObjects = new_object_addresses(); - ListCell *l; foreach(l, oids_to_drop) { ObjectAddress object; object.classId = RelationRelationId; object.objectId = lfirst_oid(l); object.objectSubId = 0; Assert(!object_address_present(&object, targetObjects)); add_exact_object_address(&object, targetObjects); } /* * Since this is an automatic drop, rather than one directly initiated * by the user, we pass the PERFORM_DELETION_INTERNAL flag. */ performMultipleDeletions(targetObjects, DROP_CASCADE, PERFORM_DELETION_INTERNAL | PERFORM_DELETION_QUIETLY); #ifdef USE_ASSERT_CHECKING diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index dbdfe8bd2d4..3670d1f1861 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -214,46 +214,44 @@ ExecVacuum(ParseState *pstate, VacuumStmt *vacstmt, bool isTopLevel) (skip_locked ? VACOPT_SKIP_LOCKED : 0) | (analyze ? VACOPT_ANALYZE : 0) | (freeze ? VACOPT_FREEZE : 0) | (full ? VACOPT_FULL : 0) | (disable_page_skipping ? VACOPT_DISABLE_PAGE_SKIPPING : 0) | (process_toast ? VACOPT_PROCESS_TOAST : 0); /* sanity checks on options */ Assert(params.options & (VACOPT_VACUUM | VACOPT_ANALYZE)); Assert((params.options & VACOPT_VACUUM) || !(params.options & (VACOPT_FULL | VACOPT_FREEZE))); if ((params.options & VACOPT_FULL) && params.nworkers > 0) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("VACUUM FULL cannot be performed in parallel"))); /* * Make sure VACOPT_ANALYZE is specified if any column lists are present. */ if (!(params.options & VACOPT_ANALYZE)) { - ListCell *lc; - foreach(lc, vacstmt->rels) { VacuumRelation *vrel = lfirst_node(VacuumRelation, lc); if (vrel->va_cols != NIL) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("ANALYZE option must be specified when a column list is provided"))); } } /* * All freeze ages are zero if the FREEZE option is given; otherwise pass * them as -1 which means to use the default values. */ if (params.options & VACOPT_FREEZE) { params.freeze_min_age = 0; params.freeze_table_age = 0; params.multixact_freeze_min_age = 0; params.multixact_freeze_table_age = 0; } diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index ac03271882f..901dd435efd 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -749,45 +749,44 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, */ if (map == NULL) { /* * It's safe to reuse these from the partition root, as we * only process one tuple at a time (therefore we won't * overwrite needed data in slots), and the results of * projections are independent of the underlying storage. * Projections and where clauses themselves don't store state * / are independent of the underlying storage. */ onconfl->oc_ProjSlot = rootResultRelInfo->ri_onConflict->oc_ProjSlot; onconfl->oc_ProjInfo = rootResultRelInfo->ri_onConflict->oc_ProjInfo; onconfl->oc_WhereClause = rootResultRelInfo->ri_onConflict->oc_WhereClause; } else { List *onconflset; List *onconflcols; - bool found_whole_row; /* * Translate expressions in onConflictSet to account for * different attribute numbers. For that, map partition * varattnos twice: first to catch the EXCLUDED * pseudo-relation (INNER_VAR), and second to handle the main * target relation (firstVarno). */ onconflset = copyObject(node->onConflictSet); if (part_attmap == NULL) part_attmap = build_attrmap_by_name(RelationGetDescr(partrel), RelationGetDescr(firstResultRel)); onconflset = (List *) map_variable_attnos((Node *) onconflset, INNER_VAR, 0, part_attmap, RelationGetForm(partrel)->reltype, &found_whole_row); /* We ignore the value of found_whole_row. */ onconflset = (List *) map_variable_attnos((Node *) onconflset, diff --git a/src/backend/executor/nodeWindowAgg.c b/src/backend/executor/nodeWindowAgg.c index 4b104c4d98a..8b0858e9f5f 100644 --- a/src/backend/executor/nodeWindowAgg.c +++ b/src/backend/executor/nodeWindowAgg.c @@ -2043,50 +2043,51 @@ update_grouptailpos(WindowAggState *winstate) static TupleTableSlot * ExecWindowAgg(PlanState *pstate) { WindowAggState *winstate = castNode(WindowAggState, pstate); TupleTableSlot *slot; ExprContext *econtext; int i; int numfuncs; CHECK_FOR_INTERRUPTS(); if (winstate->status == WINDOWAGG_DONE) return NULL; /* * Compute frame offset values, if any, during first call (or after a * rescan). These are assumed to hold constant throughout the scan; if * user gives us a volatile expression, we'll only use its initial value. */ if (winstate->all_first) { int frameOptions = winstate->frameOptions; - ExprContext *econtext = winstate->ss.ps.ps_ExprContext; Datum value; bool isnull; int16 len; bool byval; + econtext = winstate->ss.ps.ps_ExprContext; + if (frameOptions & FRAMEOPTION_START_OFFSET) { Assert(winstate->startOffset != NULL); value = ExecEvalExprSwitchContext(winstate->startOffset, econtext, &isnull); if (isnull) ereport(ERROR, (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), errmsg("frame starting offset must not be null"))); /* copy value into query-lifespan context */ get_typlenbyval(exprType((Node *) winstate->startOffset->expr), &len, &byval); winstate->startOffsetValue = datumCopy(value, byval, len); if (frameOptions & (FRAMEOPTION_ROWS | FRAMEOPTION_GROUPS)) { /* value is known to be int8 */ int64 offset = DatumGetInt64(value); if (offset < 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE), diff --git a/src/backend/lib/integerset.c b/src/backend/lib/integerset.c index 5aff292c287..41d3abdb09c 100644 --- a/src/backend/lib/integerset.c +++ b/src/backend/lib/integerset.c @@ -546,46 +546,44 @@ intset_update_upper(IntegerSet *intset, int level, intset_node *child, intset_update_upper(intset, level + 1, (intset_node *) parent, child_key); } } /* * Does the set contain the given value? */ bool intset_is_member(IntegerSet *intset, uint64 x) { intset_node *node; intset_leaf_node *leaf; int level; int itemno; leaf_item *item; /* * The value might be in the buffer of newly-added values. */ if (intset->num_buffered_values > 0 && x >= intset->buffered_values[0]) { - int itemno; - itemno = intset_binsrch_uint64(x, intset->buffered_values, intset->num_buffered_values, false); if (itemno >= intset->num_buffered_values) return false; else return (intset->buffered_values[itemno] == x); } /* * Start from the root, and walk down the B-tree to find the right leaf * node. */ if (!intset->root) return false; node = intset->root; for (level = intset->num_levels - 1; level > 0; level--) { intset_internal_node *n = (intset_internal_node *) node; Assert(node->level == level); diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 2e7330f7bc6..10cd19e6cd9 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -1633,46 +1633,44 @@ interpret_ident_response(const char *ident_response, while (pg_isblank(*cursor)) cursor++; /* skip blanks */ if (strcmp(response_type, "USERID") != 0) return false; else { /* * It's a USERID response. Good. "cursor" should be pointing * to the colon that precedes the operating system type. */ if (*cursor != ':') return false; else { cursor++; /* Go over colon */ /* Skip over operating system field. */ while (*cursor != ':' && *cursor != '\r') cursor++; if (*cursor != ':') return false; else { - int i; /* Index into *ident_user */ - cursor++; /* Go over colon */ while (pg_isblank(*cursor)) cursor++; /* skip blanks */ /* Rest of line is user name. Copy it over. */ i = 0; while (*cursor != '\r' && i < IDENT_USERNAME_MAX) ident_user[i++] = *cursor++; ident_user[i] = '\0'; return true; } } } } } } /* * Talk to the ident server on "remote_addr" and find out who * owns the tcp connection to "local_addr" * If the username is successfully retrieved, check the usermap. * diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index d929ce34171..df86d18a604 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -4757,45 +4757,45 @@ create_final_distinct_paths(PlannerInfo *root, RelOptInfo *input_rel, * First, if we have any adequately-presorted paths, just stick a * Unique node on those. Then consider doing an explicit sort of the * cheapest input path and Unique'ing that. * * When we have DISTINCT ON, we must sort by the more rigorous of * DISTINCT and ORDER BY, else it won't have the desired behavior. * Also, if we do have to do an explicit sort, we might as well use * the more rigorous ordering to avoid a second sort later. (Note * that the parser will have ensured that one clause is a prefix of * the other.) */ List *needed_pathkeys; if (parse->hasDistinctOn && list_length(root->distinct_pathkeys) < list_length(root->sort_pathkeys)) needed_pathkeys = root->sort_pathkeys; else needed_pathkeys = root->distinct_pathkeys; foreach(lc, input_rel->pathlist) { - Path *path = (Path *) lfirst(lc); + path = (Path *) lfirst(lc); if (pathkeys_contained_in(needed_pathkeys, path->pathkeys)) { add_path(distinct_rel, (Path *) create_upper_unique_path(root, distinct_rel, path, list_length(root->distinct_pathkeys), numDistinctRows)); } } /* For explicit-sort case, always use the more rigorous clause */ if (list_length(root->distinct_pathkeys) < list_length(root->sort_pathkeys)) { needed_pathkeys = root->sort_pathkeys; /* Assert checks that parser didn't mess up... */ Assert(pathkeys_contained_in(root->distinct_pathkeys, needed_pathkeys)); } else needed_pathkeys = root->distinct_pathkeys; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 043181b586b..71052c841d7 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -634,45 +634,44 @@ generate_union_paths(SetOperationStmt *op, PlannerInfo *root, * For UNION ALL, we just need the Append path. For UNION, need to add * node(s) to remove duplicates. */ if (!op->all) path = make_union_unique(op, path, tlist, root); add_path(result_rel, path); /* * Estimate number of groups. For now we just assume the output is unique * --- this is certainly true for the UNION case, and we want worst-case * estimates anyway. */ result_rel->rows = path->rows; /* * Now consider doing the same thing using the partial paths plus Append * plus Gather. */ if (partial_paths_valid) { Path *ppath; - ListCell *lc; int parallel_workers = 0; /* Find the highest number of workers requested for any subpath. */ foreach(lc, partial_pathlist) { Path *path = lfirst(lc); parallel_workers = Max(parallel_workers, path->parallel_workers); } Assert(parallel_workers > 0); /* * If the use of parallel append is permitted, always request at least * log2(# of children) paths. We assume it can be useful to have * extra workers in this case because they will be spread out across * the children. The precise formula is just a guess; see * add_paths_to_append_rel. */ if (enable_parallel_append) { parallel_workers = Max(parallel_workers, pg_leftmost_one_pos32(list_length(partial_pathlist)) + 1); diff --git a/src/backend/statistics/dependencies.c b/src/backend/statistics/dependencies.c index c1c27e67d47..bf698c1fc3f 100644 --- a/src/backend/statistics/dependencies.c +++ b/src/backend/statistics/dependencies.c @@ -1246,45 +1246,44 @@ dependency_is_compatible_expression(Node *clause, Index relid, List *statlist, N * first argument, and pseudoconstant is the second one. */ if (!is_pseudo_constant_clause(lsecond(expr->args))) return false; clause_expr = linitial(expr->args); /* * If it's not an "=" operator, just ignore the clause, as it's not * compatible with functional dependencies. The operator is identified * simply by looking at which function it uses to estimate * selectivity. That's a bit strange, but it's what other similar * places do. */ if (get_oprrest(expr->opno) != F_EQSEL) return false; /* OK to proceed with checking "var" */ } else if (is_orclause(clause)) { BoolExpr *bool_expr = (BoolExpr *) clause; - ListCell *lc; /* start with no expression (we'll use the first match) */ *expr = NULL; foreach(lc, bool_expr->args) { Node *or_expr = NULL; /* * Had we found incompatible expression in the arguments, treat * the whole expression as incompatible. */ if (!dependency_is_compatible_expression((Node *) lfirst(lc), relid, statlist, &or_expr)) return false; if (*expr == NULL) *expr = or_expr; /* ensure all the expressions are the same */ if (!equal(or_expr, *expr)) return false; diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index c0e907d4373..aad79493e86 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -3784,46 +3784,44 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg) st->estatus = ESTATUS_META_COMMAND_ERROR; } /* * We're now waiting for an SQL command to complete, or * finished processing a metacommand, or need to sleep, or * something bad happened. */ Assert(st->state == CSTATE_WAIT_RESULT || st->state == CSTATE_END_COMMAND || st->state == CSTATE_SLEEP || st->state == CSTATE_ABORTED); break; /* * non executed conditional branch */ case CSTATE_SKIP_COMMAND: Assert(!conditional_active(st->cstack)); /* quickly skip commands until something to do... */ while (true) { - Command *command; - command = sql_script[st->use_file].commands[st->command]; /* cannot reach end of script in that state */ Assert(command != NULL); /* * if this is conditional related, update conditional * state */ if (command->type == META_COMMAND && (command->meta == META_IF || command->meta == META_ELIF || command->meta == META_ELSE || command->meta == META_ENDIF)) { switch (conditional_stack_peek(st->cstack)) { case IFSTATE_FALSE: if (command->meta == META_IF || command->meta == META_ELIF) { /* we must evaluate the condition */ @@ -3940,46 +3938,44 @@ advanceConnectionState(TState *thread, CState *st, StatsData *agg) * instead of CSTATE_START_TX. */ case CSTATE_SLEEP: pg_time_now_lazy(&now); if (now < st->sleep_until) return; /* still sleeping, nothing to do here */ /* Else done sleeping. */ st->state = CSTATE_END_COMMAND; break; /* * End of command: record stats and proceed to next command. */ case CSTATE_END_COMMAND: /* * command completed: accumulate per-command execution times * in thread-local data structure, if per-command latencies * are requested. */ if (report_per_command) { - Command *command; - pg_time_now_lazy(&now); command = sql_script[st->use_file].commands[st->command]; /* XXX could use a mutex here, but we choose not to */ addToSimpleStats(&command->stats, PG_TIME_GET_DOUBLE(now - st->stmt_begin)); } /* Go ahead with next command, to be executed or skipped */ st->command++; st->state = conditional_active(st->cstack) ? CSTATE_START_COMMAND : CSTATE_SKIP_COMMAND; break; /* * Clean up after an error. */ case CSTATE_ERROR: { TStatus tstatus; Assert(st->estatus != ESTATUS_NO_ERROR);
diff --git a/src/backend/access/gist/gistbuildbuffers.c b/src/backend/access/gist/gistbuildbuffers.c index eabf7460182..77677150aff 100644 --- a/src/backend/access/gist/gistbuildbuffers.c +++ b/src/backend/access/gist/gistbuildbuffers.c @@ -615,46 +615,45 @@ gistRelocateBuildBuffersOnSplit(GISTBuildBuffers *gfbb, GISTSTATE *giststate, * empty. */ newNodeBuffer = gistGetNodeBuffer(gfbb, giststate, BufferGetBlockNumber(si->buf), level); relocationBuffersInfos[i].nodeBuffer = newNodeBuffer; relocationBuffersInfos[i].splitinfo = si; i++; } /* * Loop through all index tuples in the buffer of the page being split, * moving them to buffers for the new pages. We try to move each tuple to * the page that will result in the lowest penalty for the leading column * or, in the case of a tie, the lowest penalty for the earliest column * that is not tied. * * The page searching logic is very similar to gistchoose(). */ while (gistPopItupFromNodeBuffer(gfbb, &oldBuf, &itup)) { float best_penalty[INDEX_MAX_KEYS]; - int i, - which; + int which; IndexTuple newtup; RelocationBufferInfo *targetBufferInfo; gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, entry, isnull); /* default to using first page (shouldn't matter) */ which = 0; /* * best_penalty[j] is the best penalty we have seen so far for column * j, or -1 when we haven't yet examined column j. Array entries to * the right of the first -1 are undefined. */ best_penalty[0] = -1; /* * Loop over possible target pages, looking for one to move this tuple * to. */ for (i = 0; i < splitPagesCount; i++) { diff --git a/src/backend/access/hash/hash_xlog.c b/src/backend/access/hash/hash_xlog.c index 2e68303cbfd..e88213c7425 100644 --- a/src/backend/access/hash/hash_xlog.c +++ b/src/backend/access/hash/hash_xlog.c @@ -221,45 +221,44 @@ hash_xlog_add_ovfl_page(XLogReaderState *record) PageSetLSN(leftpage, lsn); MarkBufferDirty(leftbuf); } if (BufferIsValid(leftbuf)) UnlockReleaseBuffer(leftbuf); UnlockReleaseBuffer(ovflbuf); /* * Note: in normal operation, we'd update the bitmap and meta page while * still holding lock on the overflow pages. But during replay it's not * necessary to hold those locks, since no other index updates can be * happening concurrently. */ if (XLogRecHasBlockRef(record, 2)) { Buffer mapbuffer; if (XLogReadBufferForRedo(record, 2, &mapbuffer) == BLK_NEEDS_REDO) { Page mappage = (Page) BufferGetPage(mapbuffer); uint32 *freep = NULL; - char *data; uint32 *bitmap_page_bit; freep = HashPageGetBitmap(mappage); data = XLogRecGetBlockData(record, 2, &datalen); bitmap_page_bit = (uint32 *) data; SETBIT(freep, *bitmap_page_bit); PageSetLSN(mappage, lsn); MarkBufferDirty(mapbuffer); } if (BufferIsValid(mapbuffer)) UnlockReleaseBuffer(mapbuffer); } if (XLogRecHasBlockRef(record, 3)) { Buffer newmapbuf; newmapbuf = XLogInitBufferForRedo(record, 3); diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index aab8d6fa4e5..3133d1e0585 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -6256,45 +6256,45 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask, return multi; } /* * Do a more thorough second pass over the multi to figure out which * member XIDs actually need to be kept. Checking the precise status of * individual members might even show that we don't need to keep anything. */ nnewmembers = 0; newmembers = palloc(sizeof(MultiXactMember) * nmembers); has_lockers = false; update_xid = InvalidTransactionId; update_committed = false; temp_xid_out = *mxid_oldest_xid_out; /* init for FRM_RETURN_IS_MULTI */ for (i = 0; i < nmembers; i++) { /* * Determine whether to keep this member or ignore it. */ if (ISUPDATE_from_mxstatus(members[i].status)) { - TransactionId xid = members[i].xid; + xid = members[i].xid; Assert(TransactionIdIsValid(xid)); if (TransactionIdPrecedes(xid, relfrozenxid)) ereport(ERROR, (errcode(ERRCODE_DATA_CORRUPTED), errmsg_internal("found update xid %u from before relfrozenxid %u", xid, relfrozenxid))); /* * It's an update; should we keep it? If the transaction is known * aborted or crashed then it's okay to ignore it, otherwise not. * Note that an updater older than cutoff_xid cannot possibly be * committed, because HeapTupleSatisfiesVacuum would have returned * HEAPTUPLE_DEAD and we would not be trying to freeze the tuple. * * As with all tuple visibility routines, it's critical to test * TransactionIdIsInProgress before TransactionIdDidCommit, * because of race conditions explained in detail in * heapam_visibility.c. */ if (TransactionIdIsCurrentTransactionId(xid) || TransactionIdIsInProgress(xid)) diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 8f7d12950e5..ec57f56adf3 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1595,45 +1595,44 @@ mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members) debug_elog2(DEBUG2, "CachePut: initializing memory context"); MXactContext = AllocSetContextCreate(TopTransactionContext, "MultiXact cache context", ALLOCSET_SMALL_SIZES); } entry = (mXactCacheEnt *) MemoryContextAlloc(MXactContext, offsetof(mXactCacheEnt, members) + nmembers * sizeof(MultiXactMember)); entry->multi = multi; entry->nmembers = nmembers; memcpy(entry->members, members, nmembers * sizeof(MultiXactMember)); /* mXactCacheGetBySet assumes the entries are sorted, so sort them */ qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator); dlist_push_head(&MXactCache, &entry->node); if (MXactCacheMembers++ >= MAX_CACHE_ENTRIES) { dlist_node *node; - mXactCacheEnt *entry; node = dlist_tail_node(&MXactCache); dlist_delete(node); MXactCacheMembers--; entry = dlist_container(mXactCacheEnt, node, node); debug_elog3(DEBUG2, "CachePut: pruning cached multi %u", entry->multi); pfree(entry); } } static char * mxstatus_to_string(MultiXactStatus status) { switch (status) { case MultiXactStatusForKeyShare: return "keysh"; case MultiXactStatusForShare: return "sh"; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index a090cada400..537845cada7 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4701,45 +4701,44 @@ XLogInitNewTimeline(TimeLineID endTLI, XLogRecPtr endOfLog, TimeLineID newTLI) /* * Make a copy of the file on the new timeline. * * Writing WAL isn't allowed yet, so there are no locking * considerations. But we should be just as tense as XLogFileInit to * avoid emplacing a bogus file. */ XLogFileCopy(newTLI, endLogSegNo, endTLI, endLogSegNo, XLogSegmentOffset(endOfLog, wal_segment_size)); } else { /* * The switch happened at a segment boundary, so just create the next * segment on the new timeline. */ int fd; fd = XLogFileInit(startLogSegNo, newTLI); if (close(fd) != 0) { - char xlogfname[MAXFNAMELEN]; int save_errno = errno; XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size); errno = save_errno; ereport(ERROR, (errcode_for_file_access(), errmsg("could not close file \"%s\": %m", xlogfname))); } } /* * Let's just make real sure there are not .ready or .done flags posted * for the new segment. */ XLogFileName(xlogfname, newTLI, startLogSegNo, wal_segment_size); XLogArchiveCleanup(xlogfname); } /* * Perform cleanup actions at the conclusion of archive recovery. */ static void diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index e7e37146f69..e6fcfc23b93 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -102,45 +102,44 @@ compute_return_type(TypeName *returnType, Oid languageOid, if (typtup) { if (!((Form_pg_type) GETSTRUCT(typtup))->typisdefined) { if (languageOid == SQLlanguageId) ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("SQL function cannot return shell type %s", TypeNameToString(returnType)))); else ereport(NOTICE, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("return type %s is only a shell", TypeNameToString(returnType)))); } rettype = typeTypeId(typtup); ReleaseSysCache(typtup); } else { char *typnam = TypeNameToString(returnType); Oid namespaceId; - AclResult aclresult; char *typname; ObjectAddress address; /* * Only C-coded functions can be I/O functions. We enforce this * restriction here mainly to prevent littering the catalogs with * shell types due to simple typos in user-defined function * definitions. */ if (languageOid != INTERNALlanguageId && languageOid != ClanguageId) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("type \"%s\" does not exist", typnam))); /* Reject if there's typmod decoration, too */ if (returnType->typmods != NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("type modifier cannot be specified for shell type \"%s\"", typnam))); @@ -1093,46 +1092,44 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt) language = "sql"; else ereport(ERROR, (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), errmsg("no language specified"))); } /* Look up the language and validate permissions */ languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language)); if (!HeapTupleIsValid(languageTuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("language \"%s\" does not exist", language), (extension_file_exists(language) ? errhint("Use CREATE EXTENSION to load the language into the database.") : 0))); languageStruct = (Form_pg_language) GETSTRUCT(languageTuple); languageOid = languageStruct->oid; if (languageStruct->lanpltrusted) { /* if trusted language, need USAGE privilege */ - AclResult aclresult; - aclresult = pg_language_aclcheck(languageOid, GetUserId(), ACL_USAGE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, OBJECT_LANGUAGE, NameStr(languageStruct->lanname)); } else { /* if untrusted language, must be superuser */ if (!superuser()) aclcheck_error(ACLCHECK_NO_PRIV, OBJECT_LANGUAGE, NameStr(languageStruct->lanname)); } languageValidator = languageStruct->lanvalidator; ReleaseSysCache(languageTuple); /* * Only superuser is allowed to create leakproof functions because * leakproof functions can see tuples which have not yet been filtered out * by security barrier views or row-level security policies. */ diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 29bc26669b0..a250a33f8cb 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -2465,45 +2465,44 @@ _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options, * there be only one query. */ if (options->must_return_tuples && plan->plancache_list == NIL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("empty query does not return tuples"))); foreach(lc1, plan->plancache_list) { CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1); List *stmt_list; ListCell *lc2; spicallbackarg.query = plansource->query_string; /* * If this is a one-shot plan, we still need to do parse analysis. */ if (plan->oneshot) { RawStmt *parsetree = plansource->raw_parse_tree; const char *src = plansource->query_string; - List *stmt_list; /* * Parameter datatypes are driven by parserSetup hook if provided, * otherwise we use the fixed parameter list. */ if (parsetree == NULL) stmt_list = NIL; else if (plan->parserSetup != NULL) { Assert(plan->nargs == 0); stmt_list = pg_analyze_and_rewrite_withcb(parsetree, src, plan->parserSetup, plan->parserSetupArg, _SPI_current->queryEnv); } else { stmt_list = pg_analyze_and_rewrite_fixedparams(parsetree, src, plan->argtypes, plan->nargs, diff --git a/src/backend/optimizer/path/indxpath.c b/src/backend/optimizer/path/indxpath.c index 7d176e7b00a..0557e945ca7 100644 --- a/src/backend/optimizer/path/indxpath.c +++ b/src/backend/optimizer/path/indxpath.c @@ -2169,45 +2169,45 @@ match_clause_to_index(PlannerInfo *root, * but what if someone builds an expression index on a constant? It's not * totally unreasonable to do so with a partial index, either.) */ if (rinfo->pseudoconstant) return; /* * If clause can't be used as an indexqual because it must wait till after * some lower-security-level restriction clause, reject it. */ if (!restriction_is_securely_promotable(rinfo, index->rel)) return; /* OK, check each index key column for a match */ for (indexcol = 0; indexcol < index->nkeycolumns; indexcol++) { IndexClause *iclause; ListCell *lc; /* Ignore duplicates */ foreach(lc, clauseset->indexclauses[indexcol]) { - IndexClause *iclause = (IndexClause *) lfirst(lc); + iclause = (IndexClause *) lfirst(lc); if (iclause->rinfo == rinfo) return; } /* OK, try to match the clause to the index column */ iclause = match_clause_to_indexcol(root, rinfo, indexcol, index); if (iclause) { /* Success, so record it */ clauseset->indexclauses[indexcol] = lappend(clauseset->indexclauses[indexcol], iclause); clauseset->nonempty = true; return; } } } /* diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index df4ca129191..b15ecc83971 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -2383,45 +2383,45 @@ finalize_plan(PlannerInfo *root, Plan *plan, /* We must run finalize_plan on the subquery */ rel = find_base_rel(root, sscan->scan.scanrelid); subquery_params = rel->subroot->outer_params; if (gather_param >= 0) subquery_params = bms_add_member(bms_copy(subquery_params), gather_param); finalize_plan(rel->subroot, sscan->subplan, gather_param, subquery_params, NULL); /* Now we can add its extParams to the parent's params */ context.paramids = bms_add_members(context.paramids, sscan->subplan->extParam); /* We need scan_params too, though */ context.paramids = bms_add_members(context.paramids, scan_params); } break; case T_FunctionScan: { FunctionScan *fscan = (FunctionScan *) plan; - ListCell *lc; + ListCell *lc; // /* * Call finalize_primnode independently on each function * expression, so that we can record which params are * referenced in each, in order to decide which need * re-evaluating during rescan. */ foreach(lc, fscan->functions) { RangeTblFunction *rtfunc = (RangeTblFunction *) lfirst(lc); finalize_primnode_context funccontext; funccontext = context; funccontext.paramids = NULL; finalize_primnode(rtfunc->funcexpr, &funccontext); /* remember results for execution */ rtfunc->funcparams = funccontext.paramids; /* add the function's params to the overall set */ context.paramids = bms_add_members(context.paramids, @@ -2491,158 +2491,148 @@ finalize_plan(PlannerInfo *root, Plan *plan, case T_NamedTuplestoreScan: context.paramids = bms_add_members(context.paramids, scan_params); break; case T_ForeignScan: { ForeignScan *fscan = (ForeignScan *) plan; finalize_primnode((Node *) fscan->fdw_exprs, &context); finalize_primnode((Node *) fscan->fdw_recheck_quals, &context); /* We assume fdw_scan_tlist cannot contain Params */ context.paramids = bms_add_members(context.paramids, scan_params); } break; case T_CustomScan: { CustomScan *cscan = (CustomScan *) plan; - ListCell *lc; + ListCell *lc; // finalize_primnode((Node *) cscan->custom_exprs, &context); /* We assume custom_scan_tlist cannot contain Params */ context.paramids = bms_add_members(context.paramids, scan_params); /* child nodes if any */ foreach(lc, cscan->custom_plans) { context.paramids = bms_add_members(context.paramids, finalize_plan(root, (Plan *) lfirst(lc), gather_param, valid_params, scan_params)); } } break; case T_ModifyTable: { ModifyTable *mtplan = (ModifyTable *) plan; /* Force descendant scan nodes to reference epqParam */ locally_added_param = mtplan->epqParam; valid_params = bms_add_member(bms_copy(valid_params), locally_added_param); scan_params = bms_add_member(bms_copy(scan_params), locally_added_param); finalize_primnode((Node *) mtplan->returningLists, &context); finalize_primnode((Node *) mtplan->onConflictSet, &context); finalize_primnode((Node *) mtplan->onConflictWhere, &context); /* exclRelTlist contains only Vars, doesn't need examination */ } break; case T_Append: { - ListCell *l; - foreach(l, ((Append *) plan)->appendplans) { context.paramids = bms_add_members(context.paramids, finalize_plan(root, (Plan *) lfirst(l), gather_param, valid_params, scan_params)); } } break; case T_MergeAppend: { - ListCell *l; - foreach(l, ((MergeAppend *) plan)->mergeplans) { context.paramids = bms_add_members(context.paramids, finalize_plan(root, (Plan *) lfirst(l), gather_param, valid_params, scan_params)); } } break; case T_BitmapAnd: { - ListCell *l; - foreach(l, ((BitmapAnd *) plan)->bitmapplans) { context.paramids = bms_add_members(context.paramids, finalize_plan(root, (Plan *) lfirst(l), gather_param, valid_params, scan_params)); } } break; case T_BitmapOr: { - ListCell *l; - foreach(l, ((BitmapOr *) plan)->bitmapplans) { context.paramids = bms_add_members(context.paramids, finalize_plan(root, (Plan *) lfirst(l), gather_param, valid_params, scan_params)); } } break; case T_NestLoop: { - ListCell *l; - finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); /* collect set of params that will be passed to right child */ foreach(l, ((NestLoop *) plan)->nestParams) { NestLoopParam *nlp = (NestLoopParam *) lfirst(l); nestloop_params = bms_add_member(nestloop_params, nlp->paramno); } } break; case T_MergeJoin: finalize_primnode((Node *) ((Join *) plan)->joinqual, &context); finalize_primnode((Node *) ((MergeJoin *) plan)->mergeclauses, &context); break; case T_HashJoin: finalize_primnode((Node *) ((Join *) plan)->joinqual, diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index 091d6e886b6..2720a2508cb 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -4300,46 +4300,45 @@ get_qual_for_range(Relation parent, PartitionBoundSpec *spec, int i, j; PartitionRangeDatum *ldatum, *udatum; PartitionKey key = RelationGetPartitionKey(parent); Expr *keyCol; Const *lower_val, *upper_val; List *lower_or_arms, *upper_or_arms; int num_or_arms, current_or_arm; ListCell *lower_or_start_datum, *upper_or_start_datum; bool need_next_lower_arm, need_next_upper_arm; if (spec->is_default) { List *or_expr_args = NIL; PartitionDesc pdesc = RelationGetPartitionDesc(parent, false); Oid *inhoids = pdesc->oids; - int nparts = pdesc->nparts, - i; + int nparts = pdesc->nparts; for (i = 0; i < nparts; i++) { Oid inhrelid = inhoids[i]; HeapTuple tuple; Datum datum; bool isnull; PartitionBoundSpec *bspec; tuple = SearchSysCache1(RELOID, inhrelid); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", inhrelid); datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, &isnull); if (isnull) elog(ERROR, "null relpartbound for relation %u", inhrelid); bspec = (PartitionBoundSpec *) stringToNode(TextDatumGetCString(datum)); if (!IsA(bspec, PartitionBoundSpec)) diff --git a/src/backend/replication/logical/reorderbuffer.c b/src/backend/replication/logical/reorderbuffer.c index 89cf9f9389c..8ac78a6cf38 100644 --- a/src/backend/replication/logical/reorderbuffer.c +++ b/src/backend/replication/logical/reorderbuffer.c @@ -2301,45 +2301,44 @@ ReorderBufferProcessTXN(ReorderBuffer *rb, ReorderBufferTXN *txn, * previous tuple's toast chunks. */ Assert(change->data.tp.clear_toast_afterwards); ReorderBufferToastReset(rb, txn); /* We don't need this record anymore. */ ReorderBufferReturnChange(rb, specinsert, true); specinsert = NULL; } break; case REORDER_BUFFER_CHANGE_TRUNCATE: { int i; int nrelids = change->data.truncate.nrelids; int nrelations = 0; Relation *relations; relations = palloc0(nrelids * sizeof(Relation)); for (i = 0; i < nrelids; i++) { Oid relid = change->data.truncate.relids[i]; - Relation relation; relation = RelationIdGetRelation(relid); if (!RelationIsValid(relation)) elog(ERROR, "could not open relation with OID %u", relid); if (!RelationIsLogicallyLogged(relation)) continue; relations[nrelations++] = relation; } /* Apply the truncate. */ ReorderBufferApplyTruncate(rb, txn, nrelations, relations, change, streaming); for (i = 0; i < nrelations; i++) RelationClose(relations[i]); break; } diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index a233dd47585..b2a72374306 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -805,45 +805,44 @@ add_with_check_options(Relation rel, wco->polname = NULL; wco->cascaded = false; if (list_length(permissive_quals) == 1) wco->qual = (Node *) linitial(permissive_quals); else wco->qual = (Node *) makeBoolExpr(OR_EXPR, permissive_quals, -1); ChangeVarNodes(wco->qual, 1, rt_index, 0); *withCheckOptions = list_append_unique(*withCheckOptions, wco); /* * Now add WithCheckOptions for each of the restrictive policy clauses * (which will be combined together using AND). We use a separate * WithCheckOption for each restrictive policy to allow the policy * name to be included in error reports if the policy is violated. */ foreach(item, restrictive_policies) { RowSecurityPolicy *policy = (RowSecurityPolicy *) lfirst(item); Expr *qual = QUAL_FOR_WCO(policy); - WithCheckOption *wco; if (qual != NULL) { qual = copyObject(qual); ChangeVarNodes((Node *) qual, 1, rt_index, 0); wco = makeNode(WithCheckOption); wco->kind = kind; wco->relname = pstrdup(RelationGetRelationName(rel)); wco->polname = pstrdup(policy->policy_name); wco->qual = (Node *) qual; wco->cascaded = false; *withCheckOptions = list_append_unique(*withCheckOptions, wco); *hasSubLinks |= policy->hassublinks; } } } else { /* * If there were no policy clauses to check new data, add a single diff --git a/src/backend/utils/adt/rangetypes_spgist.c b/src/backend/utils/adt/rangetypes_spgist.c index 1190b8000bc..71a6053b6a0 100644 --- a/src/backend/utils/adt/rangetypes_spgist.c +++ b/src/backend/utils/adt/rangetypes_spgist.c @@ -674,73 +674,71 @@ spg_range_quad_inner_consistent(PG_FUNCTION_ARGS) if (minLower) { /* * If the centroid's lower bound is less than or equal to the * minimum lower bound, anything in the 3rd and 4th quadrants * will have an even smaller lower bound, and thus can't * match. */ if (range_cmp_bounds(typcache, ¢roidLower, minLower) <= 0) which &= (1 << 1) | (1 << 2) | (1 << 5); } if (maxLower) { /* * If the centroid's lower bound is greater than the maximum * lower bound, anything in the 1st and 2nd quadrants will * also have a greater than or equal lower bound, and thus * can't match. If the centroid's lower bound is equal to the * maximum lower bound, we can still exclude the 1st and 2nd * quadrants if we're looking for a value strictly greater * than the maximum. */ - int cmp; cmp = range_cmp_bounds(typcache, ¢roidLower, maxLower); if (cmp > 0 || (!inclusive && cmp == 0)) which &= (1 << 3) | (1 << 4) | (1 << 5); } if (minUpper) { /* * If the centroid's upper bound is less than or equal to the * minimum upper bound, anything in the 2nd and 3rd quadrants * will have an even smaller upper bound, and thus can't * match. */ if (range_cmp_bounds(typcache, ¢roidUpper, minUpper) <= 0) which &= (1 << 1) | (1 << 4) | (1 << 5); } if (maxUpper) { /* * If the centroid's upper bound is greater than the maximum * upper bound, anything in the 1st and 4th quadrants will * also have a greater than or equal upper bound, and thus * can't match. If the centroid's upper bound is equal to the * maximum upper bound, we can still exclude the 1st and 4th * quadrants if we're looking for a value strictly greater * than the maximum. */ - int cmp; cmp = range_cmp_bounds(typcache, ¢roidUpper, maxUpper); if (cmp > 0 || (!inclusive && cmp == 0)) which &= (1 << 2) | (1 << 3) | (1 << 5); } if (which == 0) break; /* no need to consider remaining conditions */ } } /* We must descend into the quadrant(s) identified by 'which' */ out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); if (needPrevious) out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes); out->nNodes = 0; /* * Elements of traversalValues should be allocated in * traversalMemoryContext */ oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext); diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 8280711f7ef..9959f6910e9 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -1284,45 +1284,44 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel); /* * Fetch the pg_am tuple of the index' access method */ ht_am = SearchSysCache1(AMOID, ObjectIdGetDatum(idxrelrec->relam)); if (!HeapTupleIsValid(ht_am)) elog(ERROR, "cache lookup failed for access method %u", idxrelrec->relam); amrec = (Form_pg_am) GETSTRUCT(ht_am); /* Fetch the index AM's API struct */ amroutine = GetIndexAmRoutine(amrec->amhandler); /* * Get the index expressions, if any. (NOTE: we do not use the relcache * versions of the expressions and predicate, because we want to display * non-const-folded expressions.) */ if (!heap_attisnull(ht_idx, Anum_pg_index_indexprs, NULL)) { Datum exprsDatum; - bool isnull; char *exprsString; exprsDatum = SysCacheGetAttr(INDEXRELID, ht_idx, Anum_pg_index_indexprs, &isnull); Assert(!isnull); exprsString = TextDatumGetCString(exprsDatum); indexprs = (List *) stringToNode(exprsString); pfree(exprsString); } else indexprs = NIL; indexpr_item = list_head(indexprs); context = deparse_context_for(get_relation_name(indrelid), indrelid); /* * Start the index definition. Note that the index's name should never be * schema-qualified, but the indexed rel's name may be. */ initStringInfo(&buf); @@ -1481,45 +1480,44 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, */ if (showTblSpc) { Oid tblspc; tblspc = get_rel_tablespace(indexrelid); if (OidIsValid(tblspc)) { if (isConstraint) appendStringInfoString(&buf, " USING INDEX"); appendStringInfo(&buf, " TABLESPACE %s", quote_identifier(get_tablespace_name(tblspc))); } } /* * If it's a partial index, decompile and append the predicate */ if (!heap_attisnull(ht_idx, Anum_pg_index_indpred, NULL)) { Node *node; Datum predDatum; - bool isnull; char *predString; /* Convert text string to node tree */ predDatum = SysCacheGetAttr(INDEXRELID, ht_idx, Anum_pg_index_indpred, &isnull); Assert(!isnull); predString = TextDatumGetCString(predDatum); node = (Node *) stringToNode(predString); pfree(predString); /* Deparse */ str = deparse_expression_pretty(node, context, false, false, prettyFlags, 0); if (isConstraint) appendStringInfo(&buf, " WHERE (%s)", str); else appendStringInfo(&buf, " WHERE %s", str); } } /* Clean up */ ReleaseSysCache(ht_idx); @@ -1926,45 +1924,44 @@ pg_get_partkeydef_worker(Oid relid, int prettyFlags, Assert(form->partrelid == relid); /* Must get partclass and partcollation the hard way */ datum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partitioned_table_partclass, &isnull); Assert(!isnull); partclass = (oidvector *) DatumGetPointer(datum); datum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partitioned_table_partcollation, &isnull); Assert(!isnull); partcollation = (oidvector *) DatumGetPointer(datum); /* * Get the expressions, if any. (NOTE: we do not use the relcache * versions of the expressions, because we want to display * non-const-folded expressions.) */ if (!heap_attisnull(tuple, Anum_pg_partitioned_table_partexprs, NULL)) { Datum exprsDatum; - bool isnull; char *exprsString; exprsDatum = SysCacheGetAttr(PARTRELID, tuple, Anum_pg_partitioned_table_partexprs, &isnull); Assert(!isnull); exprsString = TextDatumGetCString(exprsDatum); partexprs = (List *) stringToNode(exprsString); if (!IsA(partexprs, List)) elog(ERROR, "unexpected node type found in partexprs: %d", (int) nodeTag(partexprs)); pfree(exprsString); } else partexprs = NIL; partexpr_item = list_head(partexprs); context = deparse_context_for(get_relation_name(relid), relid); initStringInfo(&buf);