diff options
Diffstat (limited to 'src/backend')
80 files changed, 1290 insertions, 1382 deletions
diff --git a/src/backend/access/brin/brin_minmax_multi.c b/src/backend/access/brin/brin_minmax_multi.c index c87f1b9cd7e..f8a11444d66 100644 --- a/src/backend/access/brin/brin_minmax_multi.c +++ b/src/backend/access/brin/brin_minmax_multi.c @@ -276,7 +276,7 @@ static int compare_values(const void *a, const void *b, void *arg); * function (which should be BTLessStrategyNumber). */ static void -AssertArrayOrder(FmgrInfo *cmp, Oid colloid, Datum *values, int nvalues) +AssertArrayOrder(FmgrInfo *cmp, Oid colloid, const Datum *values, int nvalues) { int i; Datum lt; diff --git a/src/backend/access/common/tidstore.c b/src/backend/access/common/tidstore.c index 5bd75fb499c..fb807d9fe59 100644 --- a/src/backend/access/common/tidstore.c +++ b/src/backend/access/common/tidstore.c @@ -418,7 +418,7 @@ TidStoreSetBlockOffsets(TidStore *ts, BlockNumber blkno, OffsetNumber *offsets, /* Return true if the given TID is present in the TidStore */ bool -TidStoreIsMember(TidStore *ts, ItemPointer tid) +TidStoreIsMember(TidStore *ts, const ItemPointerData *tid) { int wordnum; int bitnum; diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c index 656299b1b52..0d4108d05a3 100644 --- a/src/backend/access/gin/ginget.c +++ b/src/backend/access/gin/ginget.c @@ -489,7 +489,7 @@ restartScanEntry: static int entryIndexByFrequencyCmp(const void *a1, const void *a2, void *arg) { - const GinScanKey key = (const GinScanKey) arg; + const GinScanKeyData *key = arg; int i1 = *(const int *) a1; int i2 = *(const int *) a2; uint32 n1 = key->scanEntry[i1]->predictNumberResult; diff --git a/src/backend/access/gin/ginpostinglist.c b/src/backend/access/gin/ginpostinglist.c index 48eadec87b0..1bf061803da 100644 --- a/src/backend/access/gin/ginpostinglist.c +++ b/src/backend/access/gin/ginpostinglist.c @@ -84,7 +84,7 @@ #define MaxBytesPerInteger 7 static inline uint64 -itemptr_to_uint64(const ItemPointer iptr) +itemptr_to_uint64(const ItemPointerData *iptr) { uint64 val; @@ -194,7 +194,7 @@ decode_varbyte(unsigned char **ptr) * byte at the end, if any, is zero. */ GinPostingList * -ginCompressPostingList(const ItemPointer ipd, int nipd, int maxsize, +ginCompressPostingList(const ItemPointerData *ipd, int nipd, int maxsize, int *nwritten) { uint64 prev; diff --git a/src/backend/access/hash/hashsort.c b/src/backend/access/hash/hashsort.c index 6e8c0e68a92..92ae3cf53f5 100644 --- a/src/backend/access/hash/hashsort.c +++ b/src/backend/access/hash/hashsort.c @@ -106,7 +106,7 @@ _h_spooldestroy(HSpool *hspool) * spool an index entry into the sort file. */ void -_h_spool(HSpool *hspool, ItemPointer self, const Datum *values, const bool *isnull) +_h_spool(HSpool *hspool, const ItemPointerData *self, const Datum *values, const bool *isnull) { tuplesort_putindextuplevalues(hspool->sortstate, hspool->index, self, values, isnull); diff --git a/src/backend/access/hash/hashutil.c b/src/backend/access/hash/hashutil.c index 66c39f60654..f41233fcd07 100644 --- a/src/backend/access/hash/hashutil.c +++ b/src/backend/access/hash/hashutil.c @@ -316,7 +316,7 @@ _hash_get_indextuple_hashkey(IndexTuple itup) */ bool _hash_convert_tuple(Relation index, - Datum *user_values, bool *user_isnull, + const Datum *user_values, const bool *user_isnull, Datum *index_values, bool *index_isnull) { uint32 hashkey; diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index 568696333c2..36fee9c994e 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -63,7 +63,7 @@ static XLogRecPtr log_heap_update(Relation reln, Buffer oldbuf, bool all_visible_cleared, bool new_all_visible_cleared); #ifdef USE_ASSERT_CHECKING static void check_lock_if_inplace_updateable_rel(Relation relation, - ItemPointer otid, + const ItemPointerData *otid, HeapTuple newtup); static void check_inplace_rel_lock(HeapTuple oldtup); #endif @@ -72,7 +72,7 @@ static Bitmapset *HeapDetermineColumnsInfo(Relation relation, Bitmapset *external_cols, HeapTuple oldtup, HeapTuple newtup, bool *has_external); -static bool heap_acquire_tuplock(Relation relation, ItemPointer tid, +static bool heap_acquire_tuplock(Relation relation, const ItemPointerData *tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock); static inline BlockNumber heapgettup_advance_block(HeapScanDesc scan, @@ -86,7 +86,7 @@ static void compute_new_xmax_infomask(TransactionId xmax, uint16 old_infomask, TransactionId *result_xmax, uint16 *result_infomask, uint16 *result_infomask2); static TM_Result heap_lock_updated_tuple(Relation rel, HeapTuple tuple, - ItemPointer ctid, TransactionId xid, + const ItemPointerData *ctid, TransactionId xid, LockTupleMode mode); static void GetMultiXactIdHintBits(MultiXactId multi, uint16 *new_infomask, uint16 *new_infomask2); @@ -95,7 +95,7 @@ static TransactionId MultiXactIdGetUpdateXid(TransactionId xmax, static bool DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, LockTupleMode lockmode, bool *current_is_member); static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, - Relation rel, ItemPointer ctid, XLTW_Oper oper, + Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining); static bool ConditionalMultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, Relation rel, int *remaining, @@ -2786,7 +2786,7 @@ xmax_infomask_changed(uint16 new_infomask, uint16 old_infomask) * generated by another transaction). */ TM_Result -heap_delete(Relation relation, ItemPointer tid, +heap_delete(Relation relation, const ItemPointerData *tid, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, bool changingPart) { @@ -3209,7 +3209,7 @@ l1: * via ereport(). */ void -simple_heap_delete(Relation relation, ItemPointer tid) +simple_heap_delete(Relation relation, const ItemPointerData *tid) { TM_Result result; TM_FailureData tmfd; @@ -3255,7 +3255,7 @@ simple_heap_delete(Relation relation, ItemPointer tid) * generated by another transaction). */ TM_Result -heap_update(Relation relation, ItemPointer otid, HeapTuple newtup, +heap_update(Relation relation, const ItemPointerData *otid, HeapTuple newtup, CommandId cid, Snapshot crosscheck, bool wait, TM_FailureData *tmfd, LockTupleMode *lockmode, TU_UpdateIndexes *update_indexes) @@ -4238,7 +4238,7 @@ l2: */ static void check_lock_if_inplace_updateable_rel(Relation relation, - ItemPointer otid, + const ItemPointerData *otid, HeapTuple newtup) { /* LOCKTAG_TUPLE acceptable for any catalog */ @@ -4499,7 +4499,7 @@ HeapDetermineColumnsInfo(Relation relation, * via ereport(). */ void -simple_heap_update(Relation relation, ItemPointer otid, HeapTuple tup, +simple_heap_update(Relation relation, const ItemPointerData *otid, HeapTuple tup, TU_UpdateIndexes *update_indexes) { TM_Result result; @@ -5285,7 +5285,7 @@ out_unlocked: * wait_policy is Skip. */ static bool -heap_acquire_tuplock(Relation relation, ItemPointer tid, LockTupleMode mode, +heap_acquire_tuplock(Relation relation, const ItemPointerData *tid, LockTupleMode mode, LockWaitPolicy wait_policy, bool *have_tuple_lock) { if (*have_tuple_lock) @@ -5706,7 +5706,7 @@ test_lockmode_for_conflict(MultiXactStatus status, TransactionId xid, * version as well. */ static TM_Result -heap_lock_updated_tuple_rec(Relation rel, ItemPointer tid, TransactionId xid, +heap_lock_updated_tuple_rec(Relation rel, const ItemPointerData *tid, TransactionId xid, LockTupleMode mode) { TM_Result result; @@ -6051,7 +6051,7 @@ out_unlocked: * levels, because that would lead to a serializability failure. */ static TM_Result -heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid, +heap_lock_updated_tuple(Relation rel, HeapTuple tuple, const ItemPointerData *ctid, TransactionId xid, LockTupleMode mode) { /* @@ -6096,7 +6096,7 @@ heap_lock_updated_tuple(Relation rel, HeapTuple tuple, ItemPointer ctid, * An explicit confirmation WAL record also makes logical decoding simpler. */ void -heap_finish_speculative(Relation relation, ItemPointer tid) +heap_finish_speculative(Relation relation, const ItemPointerData *tid) { Buffer buffer; Page page; @@ -6183,7 +6183,7 @@ heap_finish_speculative(Relation relation, ItemPointer tid) * confirmation records. */ void -heap_abort_speculative(Relation relation, ItemPointer tid) +heap_abort_speculative(Relation relation, const ItemPointerData *tid) { TransactionId xid = GetCurrentTransactionId(); ItemId lp; @@ -7705,7 +7705,7 @@ DoesMultiXactIdConflict(MultiXactId multi, uint16 infomask, static bool Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, bool nowait, - Relation rel, ItemPointer ctid, XLTW_Oper oper, + Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining, bool logLockFailure) { bool result = true; @@ -7782,7 +7782,7 @@ Do_MultiXactIdWait(MultiXactId multi, MultiXactStatus status, */ static void MultiXactIdWait(MultiXactId multi, MultiXactStatus status, uint16 infomask, - Relation rel, ItemPointer ctid, XLTW_Oper oper, + Relation rel, const ItemPointerData *ctid, XLTW_Oper oper, int *remaining) { (void) Do_MultiXactIdWait(multi, status, infomask, false, @@ -8068,7 +8068,7 @@ index_delete_prefetch_buffer(Relation rel, static inline void index_delete_check_htid(TM_IndexDeleteOp *delstate, Page page, OffsetNumber maxoff, - ItemPointer htid, TM_IndexStatus *istatus) + const ItemPointerData *htid, TM_IndexStatus *istatus) { OffsetNumber indexpagehoffnum = ItemPointerGetOffsetNumber(htid); ItemId iid; diff --git a/src/backend/access/heap/heaptoast.c b/src/backend/access/heap/heaptoast.c index cb1e57030f6..e148c9be482 100644 --- a/src/backend/access/heap/heaptoast.c +++ b/src/backend/access/heap/heaptoast.c @@ -561,8 +561,8 @@ toast_flatten_tuple_to_datum(HeapTupleHeader tup, */ HeapTuple toast_build_flattened_tuple(TupleDesc tupleDesc, - Datum *values, - bool *isnull) + const Datum *values, + const bool *isnull) { HeapTuple new_tuple; int numAttrs = tupleDesc->natts; diff --git a/src/backend/access/nbtree/nbtdedup.c b/src/backend/access/nbtree/nbtdedup.c index 07e63962f81..a746de45dd3 100644 --- a/src/backend/access/nbtree/nbtdedup.c +++ b/src/backend/access/nbtree/nbtdedup.c @@ -859,7 +859,7 @@ _bt_singleval_fillfactor(Page page, BTDedupState state, Size newitemsz) * returned posting list tuple (they must be included in htids array.) */ IndexTuple -_bt_form_posting(IndexTuple base, ItemPointer htids, int nhtids) +_bt_form_posting(IndexTuple base, const ItemPointerData *htids, int nhtids) { uint32 keysize, newsize; diff --git a/src/backend/access/nbtree/nbtpreprocesskeys.c b/src/backend/access/nbtree/nbtpreprocesskeys.c index 7b7d7860d8f..a871bf62cab 100644 --- a/src/backend/access/nbtree/nbtpreprocesskeys.c +++ b/src/backend/access/nbtree/nbtpreprocesskeys.c @@ -67,7 +67,7 @@ static int _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, int *numSkipArrayKeys_out); static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, - Datum *elems, int nelems); + const Datum *elems, int nelems); static void _bt_setup_array_cmp(IndexScanDesc scan, ScanKey skey, Oid elemtype, FmgrInfo *orderproc, FmgrInfo **sortprocp); static int _bt_sort_array_elements(ScanKey skey, FmgrInfo *sortproc, @@ -2569,7 +2569,7 @@ _bt_num_array_keys(IndexScanDesc scan, Oid *skip_eq_ops_out, static Datum _bt_find_extreme_element(IndexScanDesc scan, ScanKey skey, Oid elemtype, StrategyNumber strat, - Datum *elems, int nelems) + const Datum *elems, int nelems) { Relation rel = scan->indexRelation; Oid cmp_op; diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c index d69798795b4..7ae2bc8b66a 100644 --- a/src/backend/access/nbtree/nbtsearch.c +++ b/src/backend/access/nbtree/nbtsearch.c @@ -37,7 +37,7 @@ static bool _bt_readpage(IndexScanDesc scan, ScanDirection dir, static void _bt_saveitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum, IndexTuple itup); static int _bt_setuppostingitems(BTScanOpaque so, int itemIndex, - OffsetNumber offnum, ItemPointer heapTid, + OffsetNumber offnum, const ItemPointerData *heapTid, IndexTuple itup); static inline void _bt_savepostingitem(BTScanOpaque so, int itemIndex, OffsetNumber offnum, @@ -2079,7 +2079,7 @@ _bt_saveitem(BTScanOpaque so, int itemIndex, */ static int _bt_setuppostingitems(BTScanOpaque so, int itemIndex, OffsetNumber offnum, - ItemPointer heapTid, IndexTuple itup) + const ItemPointerData *heapTid, IndexTuple itup) { BTScanPosItem *currItem = &so->currPos.items[itemIndex]; diff --git a/src/backend/access/nbtree/nbtsort.c b/src/backend/access/nbtree/nbtsort.c index 313fe66bc96..454adaee7dc 100644 --- a/src/backend/access/nbtree/nbtsort.c +++ b/src/backend/access/nbtree/nbtsort.c @@ -257,8 +257,8 @@ typedef struct BTWriteState static double _bt_spools_heapscan(Relation heap, Relation index, BTBuildState *buildstate, IndexInfo *indexInfo); static void _bt_spooldestroy(BTSpool *btspool); -static void _bt_spool(BTSpool *btspool, ItemPointer self, - Datum *values, bool *isnull); +static void _bt_spool(BTSpool *btspool, const ItemPointerData *self, + const Datum *values, const bool *isnull); static void _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2); static void _bt_build_callback(Relation index, ItemPointer tid, Datum *values, bool *isnull, bool tupleIsAlive, void *state); @@ -525,7 +525,7 @@ _bt_spooldestroy(BTSpool *btspool) * spool an index entry into the sort file. */ static void -_bt_spool(BTSpool *btspool, ItemPointer self, Datum *values, bool *isnull) +_bt_spool(BTSpool *btspool, const ItemPointerData *self, const Datum *values, const bool *isnull) { tuplesort_putindextuplevalues(btspool->sortstate, btspool->index, self, values, isnull); diff --git a/src/backend/access/nbtree/nbtsplitloc.c b/src/backend/access/nbtree/nbtsplitloc.c index b88c396195a..f0082f88c76 100644 --- a/src/backend/access/nbtree/nbtsplitloc.c +++ b/src/backend/access/nbtree/nbtsplitloc.c @@ -69,7 +69,7 @@ static void _bt_deltasortsplits(FindSplitData *state, double fillfactormult, static int _bt_splitcmp(const void *arg1, const void *arg2); static bool _bt_afternewitemoff(FindSplitData *state, OffsetNumber maxoff, int leaffillfactor, bool *usemult); -static bool _bt_adjacenthtid(ItemPointer lowhtid, ItemPointer highhtid); +static bool _bt_adjacenthtid(const ItemPointerData *lowhtid, const ItemPointerData *highhtid); static OffsetNumber _bt_bestsplitloc(FindSplitData *state, int perfectpenalty, bool *newitemonleft, FindSplitStrat strategy); static int _bt_defaultinterval(FindSplitData *state); @@ -747,7 +747,7 @@ _bt_afternewitemoff(FindSplitData *state, OffsetNumber maxoff, * transaction. */ static bool -_bt_adjacenthtid(ItemPointer lowhtid, ItemPointer highhtid) +_bt_adjacenthtid(const ItemPointerData *lowhtid, const ItemPointerData *highhtid) { BlockNumber lowblk, highblk; diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c index e00bd0e2636..4eadb518776 100644 --- a/src/backend/access/spgist/spgdoinsert.c +++ b/src/backend/access/spgist/spgdoinsert.c @@ -1908,7 +1908,7 @@ spgSplitNodeAction(Relation index, SpGistState *state, */ bool spgdoinsert(Relation index, SpGistState *state, - ItemPointer heapPtr, Datum *datums, bool *isnulls) + const ItemPointerData *heapPtr, const Datum *datums, const bool *isnulls) { bool result = true; TupleDesc leafDescriptor = state->leafTupDesc; diff --git a/src/backend/access/spgist/spgtextproc.c b/src/backend/access/spgist/spgtextproc.c index 73842655f08..91f4ab260c2 100644 --- a/src/backend/access/spgist/spgtextproc.c +++ b/src/backend/access/spgist/spgtextproc.c @@ -155,7 +155,7 @@ commonPrefix(const char *a, const char *b, int lena, int lenb) * On success, *i gets the match location; on failure, it gets where to insert */ static bool -searchChar(Datum *nodeLabels, int nNodes, int16 c, int *i) +searchChar(const Datum *nodeLabels, int nNodes, int16 c, int *i) { int StopLow = 0, StopHigh = nNodes; diff --git a/src/backend/access/spgist/spgutils.c b/src/backend/access/spgist/spgutils.c index 245ec05e4bb..87c31da71a5 100644 --- a/src/backend/access/spgist/spgutils.c +++ b/src/backend/access/spgist/spgutils.c @@ -868,7 +868,7 @@ SpGistGetLeafTupleSize(TupleDesc tupleDescriptor, * Construct a leaf tuple containing the given heap TID and datum values */ SpGistLeafTuple -spgFormLeafTuple(SpGistState *state, ItemPointer heapPtr, +spgFormLeafTuple(SpGistState *state, const ItemPointerData *heapPtr, const Datum *datums, const bool *isnulls) { SpGistLeafTuple tup; diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index 8f8a1ad7796..71ef2e5036f 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -61,7 +61,7 @@ typedef struct spgBulkDeleteState * ensures that scans of the list don't miss items added during the scan. */ static void -spgAddPendingTID(spgBulkDeleteState *bds, ItemPointer tid) +spgAddPendingTID(spgBulkDeleteState *bds, const ItemPointerData *tid) { spgVacPendingItem *pitem; spgVacPendingItem **listLink; diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index eceab341255..fd91bcd68ec 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -749,6 +749,7 @@ XLogInsertRecord(XLogRecData *rdata, XLogRecPtr fpw_lsn, uint8 flags, int num_fpi, + uint64 fpi_bytes, bool topxid_included) { XLogCtlInsert *Insert = &XLogCtl->Insert; @@ -1081,6 +1082,7 @@ XLogInsertRecord(XLogRecData *rdata, pgWalUsage.wal_bytes += rechdr->xl_tot_len; pgWalUsage.wal_records++; pgWalUsage.wal_fpi += num_fpi; + pgWalUsage.wal_fpi_bytes += fpi_bytes; /* Required for the flush of pending stats WAL data */ pgstat_report_fixed = true; diff --git a/src/backend/access/transam/xloginsert.c b/src/backend/access/transam/xloginsert.c index 496e0fa4ac6..58cb4b1b00c 100644 --- a/src/backend/access/transam/xloginsert.c +++ b/src/backend/access/transam/xloginsert.c @@ -33,12 +33,14 @@ #include "access/xloginsert.h" #include "catalog/pg_control.h" #include "common/pg_lzcompress.h" +#include "executor/instrument.h" #include "miscadmin.h" #include "pg_trace.h" #include "replication/origin.h" #include "storage/bufmgr.h" #include "storage/proc.h" #include "utils/memutils.h" +#include "utils/pgstat_internal.h" /* * Guess the maximum buffer size required to store a compressed version of @@ -137,6 +139,7 @@ static MemoryContext xloginsert_cxt; static XLogRecData *XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecPtr RedoRecPtr, bool doPageWrites, XLogRecPtr *fpw_lsn, int *num_fpi, + uint64 *fpi_bytes, bool *topxid_included); static bool XLogCompressBackupBlock(const PageData *page, uint16 hole_offset, uint16 hole_length, void *dest, uint16 *dlen); @@ -510,6 +513,7 @@ XLogInsert(RmgrId rmid, uint8 info) XLogRecPtr fpw_lsn; XLogRecData *rdt; int num_fpi = 0; + uint64 fpi_bytes = 0; /* * Get values needed to decide whether to do full-page writes. Since @@ -519,10 +523,11 @@ XLogInsert(RmgrId rmid, uint8 info) GetFullPageWriteInfo(&RedoRecPtr, &doPageWrites); rdt = XLogRecordAssemble(rmid, info, RedoRecPtr, doPageWrites, - &fpw_lsn, &num_fpi, &topxid_included); + &fpw_lsn, &num_fpi, &fpi_bytes, + &topxid_included); EndPos = XLogInsertRecord(rdt, fpw_lsn, curinsert_flags, num_fpi, - topxid_included); + fpi_bytes, topxid_included); } while (EndPos == InvalidXLogRecPtr); XLogResetInsertion(); @@ -560,7 +565,8 @@ XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value) static XLogRecData * XLogRecordAssemble(RmgrId rmid, uint8 info, XLogRecPtr RedoRecPtr, bool doPageWrites, - XLogRecPtr *fpw_lsn, int *num_fpi, bool *topxid_included) + XLogRecPtr *fpw_lsn, int *num_fpi, uint64 *fpi_bytes, + bool *topxid_included) { XLogRecData *rdt; uint64 total_len = 0; @@ -796,6 +802,9 @@ XLogRecordAssemble(RmgrId rmid, uint8 info, } total_len += bimg.length; + + /* Track the WAL full page images in bytes */ + *fpi_bytes += bimg.length; } if (needs_data) diff --git a/src/backend/catalog/indexing.c b/src/backend/catalog/indexing.c index 25c4b6bdc87..004c5121000 100644 --- a/src/backend/catalog/indexing.c +++ b/src/backend/catalog/indexing.c @@ -310,7 +310,7 @@ CatalogTuplesMultiInsertWithInfo(Relation heapRel, TupleTableSlot **slot, * (Use CatalogTupleUpdateWithInfo in such cases.) */ void -CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup) +CatalogTupleUpdate(Relation heapRel, const ItemPointerData *otid, HeapTuple tup) { CatalogIndexState indstate; TU_UpdateIndexes updateIndexes = TU_All; @@ -334,7 +334,7 @@ CatalogTupleUpdate(Relation heapRel, ItemPointer otid, HeapTuple tup) * so that callers needn't trouble over this ... but we don't do so today. */ void -CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, +CatalogTupleUpdateWithInfo(Relation heapRel, const ItemPointerData *otid, HeapTuple tup, CatalogIndexState indstate) { TU_UpdateIndexes updateIndexes = TU_All; @@ -362,7 +362,7 @@ CatalogTupleUpdateWithInfo(Relation heapRel, ItemPointer otid, HeapTuple tup, * it might be better to do something about caching CatalogIndexState. */ void -CatalogTupleDelete(Relation heapRel, ItemPointer tid) +CatalogTupleDelete(Relation heapRel, const ItemPointerData *tid) { simple_heap_delete(heapRel, tid); } diff --git a/src/backend/catalog/pg_constraint.c b/src/backend/catalog/pg_constraint.c index 6002fd0002f..9944e4bd2d1 100644 --- a/src/backend/catalog/pg_constraint.c +++ b/src/backend/catalog/pg_constraint.c @@ -937,10 +937,12 @@ RemoveConstraintById(Oid conId) con->conrelid); classForm = (Form_pg_class) GETSTRUCT(relTup); - if (classForm->relchecks == 0) /* should not happen */ - elog(ERROR, "relation \"%s\" has relchecks = 0", - RelationGetRelationName(rel)); - classForm->relchecks--; + if (classForm->relchecks > 0) + classForm->relchecks--; + else + /* should not happen */ + elog(WARNING, "relation \"%s\" has relchecks = %d", + RelationGetRelationName(rel), classForm->relchecks); CatalogTupleUpdate(pgrel, &relTup->t_self, relTup); diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index 823776c1498..dec8df4f8ee 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -1221,6 +1221,7 @@ CREATE VIEW pg_stat_wal AS w.wal_records, w.wal_fpi, w.wal_bytes, + w.wal_fpi_bytes, w.wal_buffers_full, w.stats_reset FROM pg_stat_get_wal() w; diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index e6edae0845c..7e699f8595e 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -4283,7 +4283,8 @@ show_wal_usage(ExplainState *es, const WalUsage *usage) { /* Show only positive counter values. */ if ((usage->wal_records > 0) || (usage->wal_fpi > 0) || - (usage->wal_bytes > 0) || (usage->wal_buffers_full > 0)) + (usage->wal_bytes > 0) || (usage->wal_buffers_full > 0) || + (usage->wal_fpi_bytes > 0)) { ExplainIndentText(es); appendStringInfoString(es->str, "WAL:"); @@ -4297,6 +4298,9 @@ show_wal_usage(ExplainState *es, const WalUsage *usage) if (usage->wal_bytes > 0) appendStringInfo(es->str, " bytes=%" PRIu64, usage->wal_bytes); + if (usage->wal_fpi_bytes > 0) + appendStringInfo(es->str, " fpi bytes=%" PRIu64, + usage->wal_fpi_bytes); if (usage->wal_buffers_full > 0) appendStringInfo(es->str, " buffers full=%" PRId64, usage->wal_buffers_full); @@ -4311,6 +4315,8 @@ show_wal_usage(ExplainState *es, const WalUsage *usage) usage->wal_fpi, es); ExplainPropertyUInteger("WAL Bytes", NULL, usage->wal_bytes, es); + ExplainPropertyUInteger("WAL FPI Bytes", NULL, + usage->wal_fpi_bytes, es); ExplainPropertyInteger("WAL Buffers Full", NULL, usage->wal_buffers_full, es); } diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c index a0974d71de1..1f45444b499 100644 --- a/src/backend/commands/subscriptioncmds.c +++ b/src/backend/commands/subscriptioncmds.c @@ -1082,7 +1082,7 @@ AlterSubscription_refresh(Subscription *sub, bool copy_data, sub_remove_rels = lappend(sub_remove_rels, remove_rel); - logicalrep_worker_stop(sub->oid, relid); + logicalrep_worker_stop(WORKERTYPE_TABLESYNC, sub->oid, relid); /* * For READY state, we would have already dropped the @@ -2134,7 +2134,7 @@ DropSubscription(DropSubscriptionStmt *stmt, bool isTopLevel) { LogicalRepWorker *w = (LogicalRepWorker *) lfirst(lc); - logicalrep_worker_stop(w->subid, w->relid); + logicalrep_worker_stop(w->type, w->subid, w->relid); } list_free(subworkers); diff --git a/src/backend/executor/execGrouping.c b/src/backend/executor/execGrouping.c index 75087204f0c..b4bdaa3c305 100644 --- a/src/backend/executor/execGrouping.c +++ b/src/backend/executor/execGrouping.c @@ -20,9 +20,9 @@ #include "miscadmin.h" #include "utils/lsyscache.h" -static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2); +static int TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2); static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb, - const MinimalTuple tuple); + MinimalTuple tuple); static inline TupleHashEntry LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot, bool *isnew, uint32 hash); @@ -145,8 +145,8 @@ execTuplesHashPrepare(int numCols, * collations: collations to use in comparisons * nbuckets: initial estimate of hashtable size * additionalsize: size of data that may be stored along with the hash entry - * metacxt: memory context for long-lived allocation, but not per-entry data - * tablecxt: memory context in which to store table entries + * metacxt: memory context for long-lived data and the simplehash table + * tuplescxt: memory context in which to store the hashed tuples themselves * tempcxt: short-lived context for evaluation hash and comparison functions * use_variable_hash_iv: if true, adjust hash IV per-parallel-worker * @@ -157,11 +157,25 @@ execTuplesHashPrepare(int numCols, * Note that the keyColIdx, hashfunctions, and collations arrays must be * allocated in storage that will live as long as the hashtable does. * + * The metacxt and tuplescxt are separate because it's usually desirable for + * tuplescxt to be a BumpContext to avoid memory wastage, while metacxt must + * support pfree in case the simplehash table needs to be enlarged. (We could + * simplify the API of TupleHashTables by managing the tuplescxt internally. + * But that would be disadvantageous to nodeAgg.c and nodeSubplan.c, which use + * a single tuplescxt for multiple TupleHashTables that are reset together.) + * * LookupTupleHashEntry, FindTupleHashEntry, and related functions may leak * memory in the tempcxt. It is caller's responsibility to reset that context * reasonably often, typically once per tuple. (We do it that way, rather * than managing an extra context within the hashtable, because in many cases * the caller can specify a tempcxt that it needs to reset per-tuple anyway.) + * + * We don't currently provide DestroyTupleHashTable functionality; the hash + * table will be cleaned up at destruction of the metacxt. (Some callers + * bother to delete the tuplescxt explicitly, though it'd be sufficient to + * ensure it's a child of the metacxt.) There's not much point in working + * harder than this so long as the expression-evaluation infrastructure + * behaves similarly. */ TupleHashTable BuildTupleHashTable(PlanState *parent, @@ -175,7 +189,7 @@ BuildTupleHashTable(PlanState *parent, long nbuckets, Size additionalsize, MemoryContext metacxt, - MemoryContext tablecxt, + MemoryContext tuplescxt, MemoryContext tempcxt, bool use_variable_hash_iv) { @@ -183,14 +197,24 @@ BuildTupleHashTable(PlanState *parent, Size entrysize; Size hash_mem_limit; MemoryContext oldcontext; - bool allow_jit; uint32 hash_iv = 0; Assert(nbuckets > 0); + + /* tuplescxt must be separate, else ResetTupleHashTable breaks things */ + Assert(metacxt != tuplescxt); + + /* ensure additionalsize is maxalign'ed */ additionalsize = MAXALIGN(additionalsize); - entrysize = sizeof(TupleHashEntryData) + additionalsize; - /* Limit initial table size request to not more than hash_mem */ + /* + * Limit initial table size request to not more than hash_mem. + * + * XXX this calculation seems pretty misguided, as it counts only overhead + * and not the tuples themselves. But we have no knowledge of the + * expected tuple width here. + */ + entrysize = sizeof(TupleHashEntryData) + additionalsize; hash_mem_limit = get_hash_memory_limit() / entrysize; if (nbuckets > hash_mem_limit) nbuckets = hash_mem_limit; @@ -202,7 +226,7 @@ BuildTupleHashTable(PlanState *parent, hashtable->numCols = numCols; hashtable->keyColIdx = keyColIdx; hashtable->tab_collations = collations; - hashtable->tablecxt = tablecxt; + hashtable->tuplescxt = tuplescxt; hashtable->tempcxt = tempcxt; hashtable->additionalsize = additionalsize; hashtable->tableslot = NULL; /* will be made on first lookup */ @@ -230,16 +254,6 @@ BuildTupleHashTable(PlanState *parent, hashtable->tableslot = MakeSingleTupleTableSlot(CreateTupleDescCopy(inputDesc), &TTSOpsMinimalTuple); - /* - * If the caller fails to make the metacxt different from the tablecxt, - * allowing JIT would lead to the generated functions to a) live longer - * than the query or b) be re-generated each time the table is being - * reset. Therefore prevent JIT from being used in that case, by not - * providing a parent node (which prevents accessing the JitContext in the - * EState). - */ - allow_jit = (metacxt != tablecxt); - /* build hash ExprState for all columns */ hashtable->tab_hash_expr = ExecBuildHash32FromAttrs(inputDesc, inputOps, @@ -247,7 +261,7 @@ BuildTupleHashTable(PlanState *parent, collations, numCols, keyColIdx, - allow_jit ? parent : NULL, + parent, hash_iv); /* build comparator for all columns */ @@ -256,7 +270,7 @@ BuildTupleHashTable(PlanState *parent, &TTSOpsMinimalTuple, numCols, keyColIdx, eqfuncoids, collations, - allow_jit ? parent : NULL); + parent); /* * While not pretty, it's ok to not shut down this context, but instead @@ -273,13 +287,19 @@ BuildTupleHashTable(PlanState *parent, /* * Reset contents of the hashtable to be empty, preserving all the non-content - * state. Note that the tablecxt passed to BuildTupleHashTable() should - * also be reset, otherwise there will be leaks. + * state. + * + * Note: in usages where several TupleHashTables share a tuplescxt, all must + * be reset together, as the first one's reset call will destroy all their + * data. The additional reset calls for the rest will redundantly reset the + * tuplescxt. But because of mcxt.c's isReset flag, that's cheap enough that + * we need not avoid it. */ void ResetTupleHashTable(TupleHashTable hashtable) { tuplehash_reset(hashtable->hashtab); + MemoryContextReset(hashtable->tuplescxt); } /* @@ -419,7 +439,7 @@ FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot, */ static uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb, - const MinimalTuple tuple) + MinimalTuple tuple) { TupleHashTable hashtable = (TupleHashTable) tb->private_data; uint32 hashkey; @@ -489,10 +509,10 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot, /* created new entry */ *isnew = true; - MemoryContextSwitchTo(hashtable->tablecxt); + MemoryContextSwitchTo(hashtable->tuplescxt); /* - * Copy the first tuple into the table context, and request + * Copy the first tuple into the tuples context, and request * additionalsize extra bytes before the allocation. * * The caller can get a pointer to the additional data with @@ -517,7 +537,7 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot, * See whether two tuples (presumably of the same hash value) match */ static int -TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2) +TupleHashTableMatch(struct tuplehash_hash *tb, MinimalTuple tuple1, MinimalTuple tuple2) { TupleTableSlot *slot1; TupleTableSlot *slot2; diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c index ca33a854278..401606f840a 100644 --- a/src/backend/executor/execIndexing.c +++ b/src/backend/executor/execIndexing.c @@ -128,7 +128,7 @@ typedef enum static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, - ItemPointer tupleid, + const ItemPointerData *tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, @@ -541,7 +541,7 @@ ExecInsertIndexTuples(ResultRelInfo *resultRelInfo, bool ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, EState *estate, ItemPointer conflictTid, - ItemPointer tupleid, List *arbiterIndexes) + const ItemPointerData *tupleid, List *arbiterIndexes) { int i; int numIndices; @@ -703,7 +703,7 @@ ExecCheckIndexConstraints(ResultRelInfo *resultRelInfo, TupleTableSlot *slot, static bool check_exclusion_or_unique_constraint(Relation heap, Relation index, IndexInfo *indexInfo, - ItemPointer tupleid, + const ItemPointerData *tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex, CEOUC_WAIT_MODE waitMode, @@ -955,7 +955,7 @@ retry: void check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, - ItemPointer tupleid, + const ItemPointerData *tupleid, const Datum *values, const bool *isnull, EState *estate, bool newIndex) { diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index 1f2da072632..aa12e9ad2ea 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -173,11 +173,11 @@ static void FormPartitionKeyDatum(PartitionDispatch pd, EState *estate, Datum *values, bool *isnull); -static int get_partition_for_tuple(PartitionDispatch pd, Datum *values, - bool *isnull); +static int get_partition_for_tuple(PartitionDispatch pd, const Datum *values, + const bool *isnull); static char *ExecBuildSlotPartitionKeyDescription(Relation rel, - Datum *values, - bool *isnull, + const Datum *values, + const bool *isnull, int maxfieldlen); static List *adjust_partition_colnos(List *colnos, ResultRelInfo *leaf_part_rri); static List *adjust_partition_colnos_using_map(List *colnos, AttrMap *attrMap); @@ -1396,7 +1396,7 @@ FormPartitionKeyDatum(PartitionDispatch pd, * found or -1 if none found. */ static int -get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull) +get_partition_for_tuple(PartitionDispatch pd, const Datum *values, const bool *isnull) { int bound_offset = -1; int part_index = -1; @@ -1617,8 +1617,8 @@ get_partition_for_tuple(PartitionDispatch pd, Datum *values, bool *isnull) */ static char * ExecBuildSlotPartitionKeyDescription(Relation rel, - Datum *values, - bool *isnull, + const Datum *values, + const bool *isnull, int maxfieldlen) { StringInfoData buf; diff --git a/src/backend/executor/instrument.c b/src/backend/executor/instrument.c index 56e635f4700..9e11c662a7c 100644 --- a/src/backend/executor/instrument.c +++ b/src/backend/executor/instrument.c @@ -280,6 +280,7 @@ WalUsageAdd(WalUsage *dst, WalUsage *add) dst->wal_bytes += add->wal_bytes; dst->wal_records += add->wal_records; dst->wal_fpi += add->wal_fpi; + dst->wal_fpi_bytes += add->wal_fpi_bytes; dst->wal_buffers_full += add->wal_buffers_full; } @@ -289,5 +290,6 @@ WalUsageAccumDiff(WalUsage *dst, const WalUsage *add, const WalUsage *sub) dst->wal_bytes += add->wal_bytes - sub->wal_bytes; dst->wal_records += add->wal_records - sub->wal_records; dst->wal_fpi += add->wal_fpi - sub->wal_fpi; + dst->wal_fpi_bytes += add->wal_fpi_bytes - sub->wal_fpi_bytes; dst->wal_buffers_full += add->wal_buffers_full - sub->wal_buffers_full; } diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index 64643c3943a..759ffeed2e6 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -1457,7 +1457,7 @@ find_cols_walker(Node *node, FindColsContext *context) * We have a separate hashtable and associated perhash data structure for each * grouping set for which we're doing hashing. * - * The contents of the hash tables always live in the hashcontext's per-tuple + * The contents of the hash tables live in the aggstate's hash_tuplescxt * memory context (there is only one of these for all tables together, since * they are all reset at the same time). */ @@ -1509,7 +1509,7 @@ build_hash_table(AggState *aggstate, int setno, long nbuckets) { AggStatePerHash perhash = &aggstate->perhash[setno]; MemoryContext metacxt = aggstate->hash_metacxt; - MemoryContext tablecxt = aggstate->hash_tablecxt; + MemoryContext tuplescxt = aggstate->hash_tuplescxt; MemoryContext tmpcxt = aggstate->tmpcontext->ecxt_per_tuple_memory; Size additionalsize; @@ -1535,7 +1535,7 @@ build_hash_table(AggState *aggstate, int setno, long nbuckets) nbuckets, additionalsize, metacxt, - tablecxt, + tuplescxt, tmpcxt, DO_AGGSPLIT_SKIPFINAL(aggstate->aggsplit)); } @@ -1868,7 +1868,7 @@ hash_agg_check_limits(AggState *aggstate) uint64 ngroups = aggstate->hash_ngroups_current; Size meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true); - Size entry_mem = MemoryContextMemAllocated(aggstate->hash_tablecxt, + Size entry_mem = MemoryContextMemAllocated(aggstate->hash_tuplescxt, true); Size tval_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true); @@ -1959,7 +1959,7 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions) meta_mem = MemoryContextMemAllocated(aggstate->hash_metacxt, true); /* memory for hash entries */ - entry_mem = MemoryContextMemAllocated(aggstate->hash_tablecxt, true); + entry_mem = MemoryContextMemAllocated(aggstate->hash_tuplescxt, true); /* memory for byref transition states */ hashkey_mem = MemoryContextMemAllocated(aggstate->hashcontext->ecxt_per_tuple_memory, true); @@ -2042,11 +2042,11 @@ hash_create_memory(AggState *aggstate) /* and no smaller than ALLOCSET_DEFAULT_INITSIZE */ maxBlockSize = Max(maxBlockSize, ALLOCSET_DEFAULT_INITSIZE); - aggstate->hash_tablecxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt, - "HashAgg table context", - ALLOCSET_DEFAULT_MINSIZE, - ALLOCSET_DEFAULT_INITSIZE, - maxBlockSize); + aggstate->hash_tuplescxt = BumpContextCreate(aggstate->ss.ps.state->es_query_cxt, + "HashAgg hashed tuples", + ALLOCSET_DEFAULT_MINSIZE, + ALLOCSET_DEFAULT_INITSIZE, + maxBlockSize); } @@ -2707,7 +2707,6 @@ agg_refill_hash_table(AggState *aggstate) /* free memory and reset hash tables */ ReScanExprContext(aggstate->hashcontext); - MemoryContextReset(aggstate->hash_tablecxt); for (int setno = 0; setno < aggstate->num_hashes; setno++) ResetTupleHashTable(aggstate->perhash[setno].hashtable); @@ -4428,18 +4427,18 @@ ExecEndAgg(AggState *node) hashagg_reset_spill_state(node); + /* Release hash tables too */ if (node->hash_metacxt != NULL) { MemoryContextDelete(node->hash_metacxt); node->hash_metacxt = NULL; } - if (node->hash_tablecxt != NULL) + if (node->hash_tuplescxt != NULL) { - MemoryContextDelete(node->hash_tablecxt); - node->hash_tablecxt = NULL; + MemoryContextDelete(node->hash_tuplescxt); + node->hash_tuplescxt = NULL; } - for (transno = 0; transno < node->numtrans; transno++) { AggStatePerTrans pertrans = &node->pertrans[transno]; @@ -4555,8 +4554,7 @@ ExecReScanAgg(AggState *node) node->hash_ngroups_current = 0; ReScanExprContext(node->hashcontext); - MemoryContextReset(node->hash_tablecxt); - /* Rebuild an empty hash table */ + /* Rebuild empty hash table(s) */ build_hash_tables(node); node->table_filled = false; /* iterator will be reset when the table is filled */ diff --git a/src/backend/executor/nodeIndexscan.c b/src/backend/executor/nodeIndexscan.c index 7fcaa37fe62..f36929deec3 100644 --- a/src/backend/executor/nodeIndexscan.c +++ b/src/backend/executor/nodeIndexscan.c @@ -65,7 +65,7 @@ static int cmp_orderbyvals(const Datum *adist, const bool *anulls, static int reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, void *arg); static void reorderqueue_push(IndexScanState *node, TupleTableSlot *slot, - Datum *orderbyvals, bool *orderbynulls); + const Datum *orderbyvals, const bool *orderbynulls); static HeapTuple reorderqueue_pop(IndexScanState *node); @@ -458,7 +458,7 @@ reorderqueue_cmp(const pairingheap_node *a, const pairingheap_node *b, */ static void reorderqueue_push(IndexScanState *node, TupleTableSlot *slot, - Datum *orderbyvals, bool *orderbynulls) + const Datum *orderbyvals, const bool *orderbynulls) { IndexScanDesc scandesc = node->iss_ScanDesc; EState *estate = node->ss.ps.state; diff --git a/src/backend/executor/nodeRecursiveunion.c b/src/backend/executor/nodeRecursiveunion.c index 40f66fd0680..ebb7919b49b 100644 --- a/src/backend/executor/nodeRecursiveunion.c +++ b/src/backend/executor/nodeRecursiveunion.c @@ -53,7 +53,7 @@ build_hash_table(RecursiveUnionState *rustate) node->numGroups, 0, rustate->ps.state->es_query_cxt, - rustate->tableContext, + rustate->tuplesContext, rustate->tempContext, false); } @@ -197,7 +197,7 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) rustate->hashfunctions = NULL; rustate->hashtable = NULL; rustate->tempContext = NULL; - rustate->tableContext = NULL; + rustate->tuplesContext = NULL; /* initialize processing state */ rustate->recursing = false; @@ -209,7 +209,8 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) * If hashing, we need a per-tuple memory context for comparisons, and a * longer-lived context to store the hash table. The table can't just be * kept in the per-query context because we want to be able to throw it - * away when rescanning. + * away when rescanning. We can use a BumpContext to save storage, + * because we will have no need to delete individual table entries. */ if (node->numCols > 0) { @@ -217,10 +218,10 @@ ExecInitRecursiveUnion(RecursiveUnion *node, EState *estate, int eflags) AllocSetContextCreate(CurrentMemoryContext, "RecursiveUnion", ALLOCSET_DEFAULT_SIZES); - rustate->tableContext = - AllocSetContextCreate(CurrentMemoryContext, - "RecursiveUnion hash table", - ALLOCSET_DEFAULT_SIZES); + rustate->tuplesContext = + BumpContextCreate(CurrentMemoryContext, + "RecursiveUnion hashed tuples", + ALLOCSET_DEFAULT_SIZES); } /* @@ -288,11 +289,11 @@ ExecEndRecursiveUnion(RecursiveUnionState *node) tuplestore_end(node->working_table); tuplestore_end(node->intermediate_table); - /* free subsidiary stuff including hashtable */ + /* free subsidiary stuff including hashtable data */ if (node->tempContext) MemoryContextDelete(node->tempContext); - if (node->tableContext) - MemoryContextDelete(node->tableContext); + if (node->tuplesContext) + MemoryContextDelete(node->tuplesContext); /* * close down subplans @@ -328,10 +329,6 @@ ExecReScanRecursiveUnion(RecursiveUnionState *node) if (outerPlan->chgParam == NULL) ExecReScan(outerPlan); - /* Release any hashtable storage */ - if (node->tableContext) - MemoryContextReset(node->tableContext); - /* Empty hashtable if needed */ if (plan->numCols > 0) ResetTupleHashTable(node->hashtable); diff --git a/src/backend/executor/nodeSetOp.c b/src/backend/executor/nodeSetOp.c index 4068481a523..7b223a7ca3a 100644 --- a/src/backend/executor/nodeSetOp.c +++ b/src/backend/executor/nodeSetOp.c @@ -106,7 +106,7 @@ build_hash_table(SetOpState *setopstate) node->numGroups, sizeof(SetOpStatePerGroupData), setopstate->ps.state->es_query_cxt, - setopstate->tableContext, + setopstate->tuplesContext, econtext->ecxt_per_tuple_memory, false); } @@ -589,13 +589,15 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) /* * If hashing, we also need a longer-lived context to store the hash * table. The table can't just be kept in the per-query context because - * we want to be able to throw it away in ExecReScanSetOp. + * we want to be able to throw it away in ExecReScanSetOp. We can use a + * BumpContext to save storage, because we will have no need to delete + * individual table entries. */ if (node->strategy == SETOP_HASHED) - setopstate->tableContext = - AllocSetContextCreate(CurrentMemoryContext, - "SetOp hash table", - ALLOCSET_DEFAULT_SIZES); + setopstate->tuplesContext = + BumpContextCreate(CurrentMemoryContext, + "SetOp hashed tuples", + ALLOCSET_DEFAULT_SIZES); /* * initialize child nodes @@ -680,9 +682,9 @@ ExecInitSetOp(SetOp *node, EState *estate, int eflags) void ExecEndSetOp(SetOpState *node) { - /* free subsidiary stuff including hashtable */ - if (node->tableContext) - MemoryContextDelete(node->tableContext); + /* free subsidiary stuff including hashtable data */ + if (node->tuplesContext) + MemoryContextDelete(node->tuplesContext); ExecEndNode(outerPlanState(node)); ExecEndNode(innerPlanState(node)); @@ -721,11 +723,7 @@ ExecReScanSetOp(SetOpState *node) return; } - /* Release any hashtable storage */ - if (node->tableContext) - MemoryContextReset(node->tableContext); - - /* And rebuild an empty hashtable */ + /* Else, we must rebuild the hashtable */ ResetTupleHashTable(node->hashtable); node->table_filled = false; } diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 53fb56f7388..9f6e45bcb0b 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -506,7 +506,6 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) * saves a needless fetch inner op step for the hashing ExprState created * in BuildTupleHashTable(). */ - MemoryContextReset(node->hashtablecxt); node->havehashrows = false; node->havenullrows = false; @@ -528,7 +527,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) nbuckets, 0, node->planstate->state->es_query_cxt, - node->hashtablecxt, + node->tuplesContext, innerecontext->ecxt_per_tuple_memory, false); @@ -557,7 +556,7 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext) nbuckets, 0, node->planstate->state->es_query_cxt, - node->hashtablecxt, + node->tuplesContext, innerecontext->ecxt_per_tuple_memory, false); } @@ -838,7 +837,7 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) sstate->projRight = NULL; sstate->hashtable = NULL; sstate->hashnulls = NULL; - sstate->hashtablecxt = NULL; + sstate->tuplesContext = NULL; sstate->innerecontext = NULL; sstate->keyColIdx = NULL; sstate->tab_eq_funcoids = NULL; @@ -889,11 +888,11 @@ ExecInitSubPlan(SubPlan *subplan, PlanState *parent) *righttlist; ListCell *l; - /* We need a memory context to hold the hash table(s) */ - sstate->hashtablecxt = - AllocSetContextCreate(CurrentMemoryContext, - "Subplan HashTable Context", - ALLOCSET_DEFAULT_SIZES); + /* We need a memory context to hold the hash table(s)' tuples */ + sstate->tuplesContext = + BumpContextCreate(CurrentMemoryContext, + "SubPlan hashed tuples", + ALLOCSET_DEFAULT_SIZES); /* and a short-lived exprcontext for function evaluation */ sstate->innerecontext = CreateExprContext(estate); diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 50fcd023776..653500b38dc 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -68,7 +68,7 @@ static int _SPI_execute_plan(SPIPlanPtr plan, const SPIExecuteOptions *options, bool fire_triggers); static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, - Datum *Values, const char *Nulls); + const Datum *Values, const char *Nulls); static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount); @@ -669,7 +669,7 @@ SPI_execute_extended(const char *src, /* Execute a previously prepared plan */ int -SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, +SPI_execute_plan(SPIPlanPtr plan, const Datum *Values, const char *Nulls, bool read_only, long tcount) { SPIExecuteOptions options; @@ -771,7 +771,7 @@ SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, */ int SPI_execute_snapshot(SPIPlanPtr plan, - Datum *Values, const char *Nulls, + const Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount) { @@ -811,7 +811,7 @@ SPI_execute_snapshot(SPIPlanPtr plan, int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, - Datum *Values, const char *Nulls, + const Datum *Values, const char *Nulls, bool read_only, long tcount) { int res; @@ -1443,7 +1443,7 @@ SPI_freetuptable(SPITupleTable *tuptable) */ Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, - Datum *Values, const char *Nulls, + const Datum *Values, const char *Nulls, bool read_only) { Portal portal; @@ -2847,7 +2847,7 @@ fail: */ static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, - Datum *Values, const char *Nulls) + const Datum *Values, const char *Nulls) { ParamListInfo paramLI; diff --git a/src/backend/nodes/tidbitmap.c b/src/backend/nodes/tidbitmap.c index fac2ba5d0ca..23d97b3a6c8 100644 --- a/src/backend/nodes/tidbitmap.c +++ b/src/backend/nodes/tidbitmap.c @@ -364,7 +364,7 @@ tbm_free_shared_area(dsa_area *dsa, dsa_pointer dp) * TBMIterateResult when any of these tuples are reported out. */ void -tbm_add_tuples(TIDBitmap *tbm, const ItemPointer tids, int ntids, +tbm_add_tuples(TIDBitmap *tbm, const ItemPointerData *tids, int ntids, bool recheck) { BlockNumber currblk = InvalidBlockNumber; diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index 3b9407eb2eb..ea5b6415186 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -2260,10 +2260,20 @@ hash_inner_and_outer(PlannerInfo *root, /* * If the joinrel is parallel-safe, we may be able to consider a - * partial hash join. However, the resulting path must not be - * parameterized. + * partial hash join. + * + * However, we can't handle JOIN_RIGHT_SEMI, because the hash table is + * either a shared hash table or a private hash table per backend. In + * the shared case, there is no concurrency protection for the match + * flags, so multiple workers could inspect and set the flags + * concurrently, potentially producing incorrect results. In the + * private case, each worker has its own copy of the hash table, so no + * single process has all the match flags. + * + * Also, the resulting path must not be parameterized. */ if (joinrel->consider_parallel && + jointype != JOIN_RIGHT_SEMI && outerrel->partial_pathlist != NIL && bms_is_empty(joinrel->lateral_relids)) { @@ -2294,13 +2304,12 @@ hash_inner_and_outer(PlannerInfo *root, * Normally, given that the joinrel is parallel-safe, the cheapest * total inner path will also be parallel-safe, but if not, we'll * have to search for the cheapest safe, unparameterized inner - * path. If full, right, right-semi or right-anti join, we can't - * use parallelism (building the hash table in each backend) - * because no one process has all the match bits. + * path. If full, right, or right-anti join, we can't use + * parallelism (building the hash table in each backend) because + * no one process has all the match bits. */ if (jointype == JOIN_FULL || jointype == JOIN_RIGHT || - jointype == JOIN_RIGHT_SEMI || jointype == JOIN_RIGHT_ANTI) cheapest_safe_inner = NULL; else if (cheapest_total_inner->parallel_safe) diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index 33a040506b4..a3679f8e86c 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -339,7 +339,7 @@ hexval(unsigned char c) /* is Unicode code point acceptable? */ static void -check_unicode_value(pg_wchar c) +check_unicode_value(char32_t c) { if (!is_valid_unicode_codepoint(c)) ereport(ERROR, @@ -376,7 +376,7 @@ str_udeescape(const char *str, char escape, char *new, *out; size_t new_len; - pg_wchar pair_first = 0; + char16_t pair_first = 0; ScannerCallbackState scbstate; /* @@ -420,7 +420,7 @@ str_udeescape(const char *str, char escape, isxdigit((unsigned char) in[3]) && isxdigit((unsigned char) in[4])) { - pg_wchar unicode; + char32_t unicode; unicode = (hexval(in[1]) << 12) + (hexval(in[2]) << 8) + @@ -457,7 +457,7 @@ str_udeescape(const char *str, char escape, isxdigit((unsigned char) in[6]) && isxdigit((unsigned char) in[7])) { - pg_wchar unicode; + char32_t unicode; unicode = (hexval(in[2]) << 20) + (hexval(in[3]) << 16) + diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l index 08990831fe8..a67815339b7 100644 --- a/src/backend/parser/scan.l +++ b/src/backend/parser/scan.l @@ -121,7 +121,7 @@ static void addlitchar(unsigned char ychar, core_yyscan_t yyscanner); static char *litbufdup(core_yyscan_t yyscanner); static unsigned char unescape_single_char(unsigned char c, core_yyscan_t yyscanner); static int process_integer_literal(const char *token, YYSTYPE *lval, int base); -static void addunicode(pg_wchar c, yyscan_t yyscanner); +static void addunicode(char32_t c, yyscan_t yyscanner); #define yyerror(msg) scanner_yyerror(msg, yyscanner) @@ -640,7 +640,7 @@ other . addlit(yytext, yyleng, yyscanner); } <xe>{xeunicode} { - pg_wchar c = strtoul(yytext + 2, NULL, 16); + char32_t c = strtoul(yytext + 2, NULL, 16); /* * For consistency with other productions, issue any @@ -668,7 +668,7 @@ other . POP_YYLLOC(); } <xeu>{xeunicode} { - pg_wchar c = strtoul(yytext + 2, NULL, 16); + char32_t c = strtoul(yytext + 2, NULL, 16); /* Remember start of overall string token ... */ PUSH_YYLLOC(); @@ -1376,7 +1376,7 @@ process_integer_literal(const char *token, YYSTYPE *lval, int base) } static void -addunicode(pg_wchar c, core_yyscan_t yyscanner) +addunicode(char32_t c, core_yyscan_t yyscanner) { ScannerCallbackState scbstate; char buf[MAX_UNICODE_EQUIVALENT_STRING + 1]; diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c index 822cf4ec451..8ba038c5ef4 100644 --- a/src/backend/partitioning/partbounds.c +++ b/src/backend/partitioning/partbounds.c @@ -3555,8 +3555,8 @@ partition_rbound_cmp(int partnatts, FmgrInfo *partsupfunc, */ int32 partition_rbound_datum_cmp(FmgrInfo *partsupfunc, Oid *partcollation, - Datum *rb_datums, PartitionRangeDatumKind *rb_kind, - Datum *tuple_datums, int n_tuple_datums) + const Datum *rb_datums, PartitionRangeDatumKind *rb_kind, + const Datum *tuple_datums, int n_tuple_datums) { int i; int32 cmpval = -1; @@ -3695,7 +3695,7 @@ partition_range_bsearch(int partnatts, FmgrInfo *partsupfunc, int partition_range_datum_bsearch(FmgrInfo *partsupfunc, Oid *partcollation, PartitionBoundInfo boundinfo, - int nvalues, Datum *values, bool *is_equal) + int nvalues, const Datum *values, bool *is_equal) { int lo, hi, diff --git a/src/backend/partitioning/partprune.c b/src/backend/partitioning/partprune.c index 48a35f763e9..6fff4034c24 100644 --- a/src/backend/partitioning/partprune.c +++ b/src/backend/partitioning/partprune.c @@ -179,13 +179,13 @@ static List *get_steps_using_prefix_recurse(GeneratePruningStepsContext *context List *step_exprs, List *step_cmpfns); static PruneStepResult *get_matching_hash_bounds(PartitionPruneContext *context, - StrategyNumber opstrategy, Datum *values, int nvalues, + StrategyNumber opstrategy, const Datum *values, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys); static PruneStepResult *get_matching_list_bounds(PartitionPruneContext *context, StrategyNumber opstrategy, Datum value, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys); static PruneStepResult *get_matching_range_bounds(PartitionPruneContext *context, - StrategyNumber opstrategy, Datum *values, int nvalues, + StrategyNumber opstrategy, const Datum *values, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys); static Bitmapset *pull_exec_paramids(Expr *expr); static bool pull_exec_paramids_walker(Node *node, Bitmapset **context); @@ -2690,7 +2690,7 @@ get_steps_using_prefix_recurse(GeneratePruningStepsContext *context, */ static PruneStepResult * get_matching_hash_bounds(PartitionPruneContext *context, - StrategyNumber opstrategy, Datum *values, int nvalues, + StrategyNumber opstrategy, const Datum *values, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys) { PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); @@ -2978,7 +2978,7 @@ get_matching_list_bounds(PartitionPruneContext *context, */ static PruneStepResult * get_matching_range_bounds(PartitionPruneContext *context, - StrategyNumber opstrategy, Datum *values, int nvalues, + StrategyNumber opstrategy, const Datum *values, int nvalues, FmgrInfo *partsupfunc, Bitmapset *nullkeys) { PruneStepResult *result = (PruneStepResult *) palloc0(sizeof(PruneStepResult)); diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c index 218cefe86e2..95b5cae9a55 100644 --- a/src/backend/replication/logical/launcher.c +++ b/src/backend/replication/logical/launcher.c @@ -245,20 +245,25 @@ WaitForReplicationWorkerAttach(LogicalRepWorker *worker, } /* - * Walks the workers array and searches for one that matches given - * subscription id and relid. + * Walks the workers array and searches for one that matches given worker type, + * subscription id, and relation id. * - * We are only interested in the leader apply worker or table sync worker. + * For apply workers, the relid should be set to InvalidOid, as they manage + * changes across all tables. For table sync workers, the relid should be set + * to the OID of the relation being synchronized. */ LogicalRepWorker * -logicalrep_worker_find(Oid subid, Oid relid, bool only_running) +logicalrep_worker_find(LogicalRepWorkerType wtype, Oid subid, Oid relid, + bool only_running) { int i; LogicalRepWorker *res = NULL; + /* relid must be valid only for table sync workers */ + Assert((wtype == WORKERTYPE_TABLESYNC) == OidIsValid(relid)); Assert(LWLockHeldByMe(LogicalRepWorkerLock)); - /* Search for attached worker for a given subscription id. */ + /* Search for an attached worker that matches the specified criteria. */ for (i = 0; i < max_logical_replication_workers; i++) { LogicalRepWorker *w = &LogicalRepCtx->workers[i]; @@ -268,7 +273,7 @@ logicalrep_worker_find(Oid subid, Oid relid, bool only_running) continue; if (w->in_use && w->subid == subid && w->relid == relid && - (!only_running || w->proc)) + w->type == wtype && (!only_running || w->proc)) { res = w; break; @@ -627,16 +632,20 @@ logicalrep_worker_stop_internal(LogicalRepWorker *worker, int signo) } /* - * Stop the logical replication worker for subid/relid, if any. + * Stop the logical replication worker that matches the specified worker type, + * subscription id, and relation id. */ void -logicalrep_worker_stop(Oid subid, Oid relid) +logicalrep_worker_stop(LogicalRepWorkerType wtype, Oid subid, Oid relid) { LogicalRepWorker *worker; + /* relid must be valid only for table sync workers */ + Assert((wtype == WORKERTYPE_TABLESYNC) == OidIsValid(relid)); + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - worker = logicalrep_worker_find(subid, relid, false); + worker = logicalrep_worker_find(wtype, subid, relid, false); if (worker) { @@ -694,16 +703,20 @@ logicalrep_pa_worker_stop(ParallelApplyWorkerInfo *winfo) } /* - * Wake up (using latch) any logical replication worker for specified sub/rel. + * Wake up (using latch) any logical replication worker that matches the + * specified worker type, subscription id, and relation id. */ void -logicalrep_worker_wakeup(Oid subid, Oid relid) +logicalrep_worker_wakeup(LogicalRepWorkerType wtype, Oid subid, Oid relid) { LogicalRepWorker *worker; + /* relid must be valid only for table sync workers */ + Assert((wtype == WORKERTYPE_TABLESYNC) == OidIsValid(relid)); + LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - worker = logicalrep_worker_find(subid, relid, true); + worker = logicalrep_worker_find(wtype, subid, relid, true); if (worker) logicalrep_worker_wakeup_ptr(worker); @@ -1260,7 +1273,8 @@ ApplyLauncherMain(Datum main_arg) continue; LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - w = logicalrep_worker_find(sub->oid, InvalidOid, false); + w = logicalrep_worker_find(WORKERTYPE_APPLY, sub->oid, InvalidOid, + false); if (w != NULL) { diff --git a/src/backend/replication/logical/syncutils.c b/src/backend/replication/logical/syncutils.c index e452a1e78d4..ae8c9385916 100644 --- a/src/backend/replication/logical/syncutils.c +++ b/src/backend/replication/logical/syncutils.c @@ -69,7 +69,8 @@ FinishSyncWorker(void) CommitTransactionCommand(); /* Find the leader apply worker and signal it. */ - logicalrep_worker_wakeup(MyLogicalRepWorker->subid, InvalidOid); + logicalrep_worker_wakeup(WORKERTYPE_APPLY, MyLogicalRepWorker->subid, + InvalidOid); /* Stop gracefully */ proc_exit(0); diff --git a/src/backend/replication/logical/tablesync.c b/src/backend/replication/logical/tablesync.c index 40e1ed3c20e..58c98488d7b 100644 --- a/src/backend/replication/logical/tablesync.c +++ b/src/backend/replication/logical/tablesync.c @@ -160,7 +160,8 @@ wait_for_table_state_change(Oid relid, char expected_state) /* Check if the sync worker is still running and bail if not. */ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - worker = logicalrep_worker_find(MyLogicalRepWorker->subid, relid, + worker = logicalrep_worker_find(WORKERTYPE_TABLESYNC, + MyLogicalRepWorker->subid, relid, false); LWLockRelease(LogicalRepWorkerLock); if (!worker) @@ -207,8 +208,9 @@ wait_for_worker_state_change(char expected_state) * waiting. */ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - worker = logicalrep_worker_find(MyLogicalRepWorker->subid, - InvalidOid, false); + worker = logicalrep_worker_find(WORKERTYPE_APPLY, + MyLogicalRepWorker->subid, InvalidOid, + false); if (worker && worker->proc) logicalrep_worker_wakeup_ptr(worker); LWLockRelease(LogicalRepWorkerLock); @@ -476,7 +478,8 @@ ProcessSyncingTablesForApply(XLogRecPtr current_lsn) */ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - syncworker = logicalrep_worker_find(MyLogicalRepWorker->subid, + syncworker = logicalrep_worker_find(WORKERTYPE_TABLESYNC, + MyLogicalRepWorker->subid, rstate->relid, false); if (syncworker) diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c index 5df5a4612b6..7edd1c9cf06 100644 --- a/src/backend/replication/logical/worker.c +++ b/src/backend/replication/logical/worker.c @@ -1817,7 +1817,8 @@ apply_handle_stream_start(StringInfo s) * Signal the leader apply worker, as it may be waiting for * us. */ - logicalrep_worker_wakeup(MyLogicalRepWorker->subid, InvalidOid); + logicalrep_worker_wakeup(WORKERTYPE_APPLY, + MyLogicalRepWorker->subid, InvalidOid); } parallel_stream_nchanges = 0; @@ -3284,8 +3285,9 @@ FindDeletedTupleInLocalRel(Relation localrel, Oid localidxoid, * maybe_advance_nonremovable_xid() for details). */ LWLockAcquire(LogicalRepWorkerLock, LW_SHARED); - leader = logicalrep_worker_find(MyLogicalRepWorker->subid, - InvalidOid, false); + leader = logicalrep_worker_find(WORKERTYPE_APPLY, + MyLogicalRepWorker->subid, InvalidOid, + false); if (!leader) { ereport(ERROR, diff --git a/src/backend/replication/slot.c b/src/backend/replication/slot.c index 1e9f4602c69..6363030808f 100644 --- a/src/backend/replication/slot.c +++ b/src/backend/replication/slot.c @@ -1746,17 +1746,16 @@ static ReplicationSlotInvalidationCause DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s, XLogRecPtr oldestLSN, Oid dboid, TransactionId snapshotConflictHorizon, - TransactionId initial_effective_xmin, - TransactionId initial_catalog_effective_xmin, - XLogRecPtr initial_restart_lsn, TimestampTz *inactive_since, TimestampTz now) { Assert(possible_causes != RS_INVAL_NONE); if (possible_causes & RS_INVAL_WAL_REMOVED) { - if (initial_restart_lsn != InvalidXLogRecPtr && - initial_restart_lsn < oldestLSN) + XLogRecPtr restart_lsn = s->data.restart_lsn; + + if (restart_lsn != InvalidXLogRecPtr && + restart_lsn < oldestLSN) return RS_INVAL_WAL_REMOVED; } @@ -1766,12 +1765,15 @@ DetermineSlotInvalidationCause(uint32 possible_causes, ReplicationSlot *s, if (SlotIsLogical(s) && (dboid == InvalidOid || dboid == s->data.database)) { - if (TransactionIdIsValid(initial_effective_xmin) && - TransactionIdPrecedesOrEquals(initial_effective_xmin, + TransactionId effective_xmin = s->effective_xmin; + TransactionId catalog_effective_xmin = s->effective_catalog_xmin; + + if (TransactionIdIsValid(effective_xmin) && + TransactionIdPrecedesOrEquals(effective_xmin, snapshotConflictHorizon)) return RS_INVAL_HORIZON; - else if (TransactionIdIsValid(initial_catalog_effective_xmin) && - TransactionIdPrecedesOrEquals(initial_catalog_effective_xmin, + else if (TransactionIdIsValid(catalog_effective_xmin) && + TransactionIdPrecedesOrEquals(catalog_effective_xmin, snapshotConflictHorizon)) return RS_INVAL_HORIZON; } @@ -1840,11 +1842,6 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes, { int last_signaled_pid = 0; bool released_lock = false; - bool terminated = false; - TransactionId initial_effective_xmin = InvalidTransactionId; - TransactionId initial_catalog_effective_xmin = InvalidTransactionId; - XLogRecPtr initial_restart_lsn = InvalidXLogRecPtr; - ReplicationSlotInvalidationCause invalidation_cause_prev PG_USED_FOR_ASSERTS_ONLY = RS_INVAL_NONE; TimestampTz inactive_since = 0; for (;;) @@ -1887,42 +1884,12 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes, /* we do nothing if the slot is already invalid */ if (s->data.invalidated == RS_INVAL_NONE) - { - /* - * The slot's mutex will be released soon, and it is possible that - * those values change since the process holding the slot has been - * terminated (if any), so record them here to ensure that we - * would report the correct invalidation cause. - * - * Unlike other slot attributes, slot's inactive_since can't be - * changed until the acquired slot is released or the owning - * process is terminated. So, the inactive slot can only be - * invalidated immediately without being terminated. - */ - if (!terminated) - { - initial_restart_lsn = s->data.restart_lsn; - initial_effective_xmin = s->effective_xmin; - initial_catalog_effective_xmin = s->effective_catalog_xmin; - } - invalidation_cause = DetermineSlotInvalidationCause(possible_causes, s, oldestLSN, dboid, snapshotConflictHorizon, - initial_effective_xmin, - initial_catalog_effective_xmin, - initial_restart_lsn, &inactive_since, now); - } - - /* - * The invalidation cause recorded previously should not change while - * the process owning the slot (if any) has been terminated. - */ - Assert(!(invalidation_cause_prev != RS_INVAL_NONE && terminated && - invalidation_cause_prev != invalidation_cause)); /* if there's no invalidation, we're done */ if (invalidation_cause == RS_INVAL_NONE) @@ -1940,6 +1907,11 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes, * If the slot can be acquired, do so and mark it invalidated * immediately. Otherwise we'll signal the owning process, below, and * retry. + * + * Note: Unlike other slot attributes, slot's inactive_since can't be + * changed until the acquired slot is released or the owning process + * is terminated. So, the inactive slot can only be invalidated + * immediately without being terminated. */ if (active_pid == 0) { @@ -2014,8 +1986,6 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes, (void) kill(active_pid, SIGTERM); last_signaled_pid = active_pid; - terminated = true; - invalidation_cause_prev = invalidation_cause; } /* Wait until the slot is released. */ @@ -2026,6 +1996,14 @@ InvalidatePossiblyObsoleteSlot(uint32 possible_causes, * Re-acquire lock and start over; we expect to invalidate the * slot next time (unless another process acquires the slot in the * meantime). + * + * Note: It is possible for a slot to advance its restart_lsn or + * xmin values sufficiently between when we release the mutex and + * when we recheck, moving from a conflicting state to a non + * conflicting state. This is intentional and safe: if the slot + * has caught up while we're busy here, the resources we were + * concerned about (WAL segments or tuples) have not yet been + * removed, and there's no reason to invalidate the slot. */ LWLockAcquire(ReplicationSlotControlLock, LW_SHARED); continue; diff --git a/src/backend/statistics/attribute_stats.c b/src/backend/statistics/attribute_stats.c index c5df83282e0..401bf571f27 100644 --- a/src/backend/statistics/attribute_stats.c +++ b/src/backend/statistics/attribute_stats.c @@ -115,7 +115,7 @@ static void set_stats_slot(Datum *values, bool *nulls, bool *replaces, Datum stanumbers, bool stanumbers_isnull, Datum stavalues, bool stavalues_isnull); static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, - Datum *values, bool *nulls, bool *replaces); + const Datum *values, const bool *nulls, const bool *replaces); static bool delete_pg_statistic(Oid reloid, AttrNumber attnum, bool stainherit); static void init_empty_stats_tuple(Oid reloid, int16 attnum, bool inherited, Datum *values, bool *nulls, bool *replaces); @@ -819,7 +819,7 @@ set_stats_slot(Datum *values, bool *nulls, bool *replaces, */ static void upsert_pg_statistic(Relation starel, HeapTuple oldtup, - Datum *values, bool *nulls, bool *replaces) + const Datum *values, const bool *nulls, const bool *replaces) { HeapTuple newtup; diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c index c1d8511ad17..bb807d8c9cd 100644 --- a/src/backend/storage/lmgr/predicate.c +++ b/src/backend/storage/lmgr/predicate.c @@ -168,7 +168,7 @@ * PredicateLockRelation(Relation relation, Snapshot snapshot) * PredicateLockPage(Relation relation, BlockNumber blkno, * Snapshot snapshot) - * PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot, + * PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot, * TransactionId tuple_xid) * PredicateLockPageSplit(Relation relation, BlockNumber oldblkno, * BlockNumber newblkno) @@ -180,7 +180,7 @@ * conflict detection (may also trigger rollback) * CheckForSerializableConflictOut(Relation relation, TransactionId xid, * Snapshot snapshot) - * CheckForSerializableConflictIn(Relation relation, ItemPointer tid, + * CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, * BlockNumber blkno) * CheckTableForSerializableConflictIn(Relation relation) * @@ -2618,7 +2618,7 @@ PredicateLockPage(Relation relation, BlockNumber blkno, Snapshot snapshot) * Skip if this is a temporary table. */ void -PredicateLockTID(Relation relation, ItemPointer tid, Snapshot snapshot, +PredicateLockTID(Relation relation, const ItemPointerData *tid, Snapshot snapshot, TransactionId tuple_xid) { PREDICATELOCKTARGETTAG tag; @@ -4333,7 +4333,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag) * tuple itself. */ void -CheckForSerializableConflictIn(Relation relation, ItemPointer tid, BlockNumber blkno) +CheckForSerializableConflictIn(Relation relation, const ItemPointerData *tid, BlockNumber blkno) { PREDICATELOCKTARGETTAG targettag; diff --git a/src/backend/storage/page/itemptr.c b/src/backend/storage/page/itemptr.c index ad658215721..cedb27d6cc5 100644 --- a/src/backend/storage/page/itemptr.c +++ b/src/backend/storage/page/itemptr.c @@ -32,7 +32,7 @@ StaticAssertDecl(sizeof(ItemPointerData) == 3 * sizeof(uint16), * Asserts that the disk item pointers are both valid! */ bool -ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2) +ItemPointerEquals(const ItemPointerData *pointer1, const ItemPointerData *pointer2) { if (ItemPointerGetBlockNumber(pointer1) == ItemPointerGetBlockNumber(pointer2) && @@ -48,7 +48,7 @@ ItemPointerEquals(ItemPointer pointer1, ItemPointer pointer2) * Generic btree-style comparison for item pointers. */ int32 -ItemPointerCompare(ItemPointer arg1, ItemPointer arg2) +ItemPointerCompare(const ItemPointerData *arg1, const ItemPointerData *arg2) { /* * Use ItemPointerGet{Offset,Block}NumberNoCheck to avoid asserting diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 08791b8f75e..74179139fa9 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -165,27 +165,22 @@ ProcessQuery(PlannedStmt *plan, */ if (qc) { - switch (queryDesc->operation) - { - case CMD_SELECT: - SetQueryCompletion(qc, CMDTAG_SELECT, queryDesc->estate->es_processed); - break; - case CMD_INSERT: - SetQueryCompletion(qc, CMDTAG_INSERT, queryDesc->estate->es_processed); - break; - case CMD_UPDATE: - SetQueryCompletion(qc, CMDTAG_UPDATE, queryDesc->estate->es_processed); - break; - case CMD_DELETE: - SetQueryCompletion(qc, CMDTAG_DELETE, queryDesc->estate->es_processed); - break; - case CMD_MERGE: - SetQueryCompletion(qc, CMDTAG_MERGE, queryDesc->estate->es_processed); - break; - default: - SetQueryCompletion(qc, CMDTAG_UNKNOWN, queryDesc->estate->es_processed); - break; - } + CommandTag tag; + + if (queryDesc->operation == CMD_SELECT) + tag = CMDTAG_SELECT; + else if (queryDesc->operation == CMD_INSERT) + tag = CMDTAG_INSERT; + else if (queryDesc->operation == CMD_UPDATE) + tag = CMDTAG_UPDATE; + else if (queryDesc->operation == CMD_DELETE) + tag = CMDTAG_DELETE; + else if (queryDesc->operation == CMD_MERGE) + tag = CMDTAG_MERGE; + else + tag = CMDTAG_UNKNOWN; + + SetQueryCompletion(qc, tag, queryDesc->estate->es_processed); } /* diff --git a/src/backend/tsearch/ts_selfuncs.c b/src/backend/tsearch/ts_selfuncs.c index 6a71ae6452d..fb367ad74d2 100644 --- a/src/backend/tsearch/ts_selfuncs.c +++ b/src/backend/tsearch/ts_selfuncs.c @@ -47,8 +47,8 @@ typedef struct static Selectivity tsquerysel(VariableStatData *vardata, Datum constval); static Selectivity mcelem_tsquery_selec(TSQuery query, - Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers); + const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers); static Selectivity tsquery_opr_selec(QueryItem *item, char *operand, TextFreq *lookup, int length, float4 minfreq); static int compare_lexeme_textfreq(const void *e1, const void *e2); @@ -204,8 +204,8 @@ tsquerysel(VariableStatData *vardata, Datum constval) * Extract data from the pg_statistic arrays into useful format. */ static Selectivity -mcelem_tsquery_selec(TSQuery query, Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers) +mcelem_tsquery_selec(TSQuery query, const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers) { float4 minfreq; TextFreq *lookup; diff --git a/src/backend/utils/activity/pgstat_backend.c b/src/backend/utils/activity/pgstat_backend.c index a864ae8e6a6..199ba2cc17a 100644 --- a/src/backend/utils/activity/pgstat_backend.c +++ b/src/backend/utils/activity/pgstat_backend.c @@ -252,6 +252,7 @@ pgstat_flush_backend_entry_wal(PgStat_EntryRef *entry_ref) WALSTAT_ACC(wal_records, wal_usage_diff); WALSTAT_ACC(wal_fpi, wal_usage_diff); WALSTAT_ACC(wal_bytes, wal_usage_diff); + WALSTAT_ACC(wal_fpi_bytes, wal_usage_diff); #undef WALSTAT_ACC /* diff --git a/src/backend/utils/activity/pgstat_wal.c b/src/backend/utils/activity/pgstat_wal.c index 0d04480d2f6..d4edb8b5733 100644 --- a/src/backend/utils/activity/pgstat_wal.c +++ b/src/backend/utils/activity/pgstat_wal.c @@ -121,6 +121,7 @@ pgstat_wal_flush_cb(bool nowait) WALSTAT_ACC(wal_records, wal_usage_diff); WALSTAT_ACC(wal_fpi, wal_usage_diff); WALSTAT_ACC(wal_bytes, wal_usage_diff); + WALSTAT_ACC(wal_fpi_bytes, wal_usage_diff); WALSTAT_ACC(wal_buffers_full, wal_usage_diff); #undef WALSTAT_ACC diff --git a/src/backend/utils/adt/array_selfuncs.c b/src/backend/utils/adt/array_selfuncs.c index cf6fbf8652c..4dab35b0057 100644 --- a/src/backend/utils/adt/array_selfuncs.c +++ b/src/backend/utils/adt/array_selfuncs.c @@ -39,25 +39,25 @@ static Selectivity calc_arraycontsel(VariableStatData *vardata, Datum constval, Oid elemtype, Oid operator); -static Selectivity mcelem_array_selec(ArrayType *array, +static Selectivity mcelem_array_selec(const ArrayType *array, TypeCacheEntry *typentry, - Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - float4 *hist, int nhist, + const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const float4 *hist, int nhist, Oid operator); -static Selectivity mcelem_array_contain_overlap_selec(Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - Datum *array_data, int nitems, +static Selectivity mcelem_array_contain_overlap_selec(const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const Datum *array_data, int nitems, Oid operator, TypeCacheEntry *typentry); -static Selectivity mcelem_array_contained_selec(Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - Datum *array_data, int nitems, - float4 *hist, int nhist, +static Selectivity mcelem_array_contained_selec(const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const Datum *array_data, int nitems, + const float4 *hist, int nhist, Oid operator, TypeCacheEntry *typentry); static float *calc_hist(const float4 *hist, int nhist, int n); static float *calc_distr(const float *p, int n, int m, float rest); static int floor_log2(uint32 n); -static bool find_next_mcelem(Datum *mcelem, int nmcelem, Datum value, +static bool find_next_mcelem(const Datum *mcelem, int nmcelem, Datum value, int *index, TypeCacheEntry *typentry); static int element_compare(const void *key1, const void *key2, void *arg); static int float_compare_desc(const void *key1, const void *key2); @@ -425,10 +425,10 @@ calc_arraycontsel(VariableStatData *vardata, Datum constval, * mcelem_array_contained_selec depending on the operator. */ static Selectivity -mcelem_array_selec(ArrayType *array, TypeCacheEntry *typentry, - Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - float4 *hist, int nhist, +mcelem_array_selec(const ArrayType *array, TypeCacheEntry *typentry, + const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const float4 *hist, int nhist, Oid operator) { Selectivity selec; @@ -518,9 +518,9 @@ mcelem_array_selec(ArrayType *array, TypeCacheEntry *typentry, * fraction of nonempty arrays in the column. */ static Selectivity -mcelem_array_contain_overlap_selec(Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - Datum *array_data, int nitems, +mcelem_array_contain_overlap_selec(const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const Datum *array_data, int nitems, Oid operator, TypeCacheEntry *typentry) { Selectivity selec, @@ -699,10 +699,10 @@ mcelem_array_contain_overlap_selec(Datum *mcelem, int nmcelem, * ... * fn^on * (1 - fn)^(1 - on), o1, o2, ..., on) | o1 + o2 + .. on = m */ static Selectivity -mcelem_array_contained_selec(Datum *mcelem, int nmcelem, - float4 *numbers, int nnumbers, - Datum *array_data, int nitems, - float4 *hist, int nhist, +mcelem_array_contained_selec(const Datum *mcelem, int nmcelem, + const float4 *numbers, int nnumbers, + const Datum *array_data, int nitems, + const float4 *hist, int nhist, Oid operator, TypeCacheEntry *typentry) { int mcelem_index, @@ -1136,7 +1136,7 @@ floor_log2(uint32 n) * exact match.) */ static bool -find_next_mcelem(Datum *mcelem, int nmcelem, Datum value, int *index, +find_next_mcelem(const Datum *mcelem, int nmcelem, Datum value, int *index, TypeCacheEntry *typentry) { int l = *index, diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index a8951f55b93..a464349ee33 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -960,8 +960,8 @@ ending_error: */ void CopyArrayEls(ArrayType *array, - Datum *values, - bool *nulls, + const Datum *values, + const bool *nulls, int nitems, int typlen, bool typbyval, @@ -3629,7 +3629,7 @@ construct_empty_expanded_array(Oid element_type, * to hard-wire values if the element type is hard-wired. */ void -deconstruct_array(ArrayType *array, +deconstruct_array(const ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp) @@ -3695,7 +3695,7 @@ deconstruct_array(ArrayType *array, * useful when manipulating arrays from/for system catalogs. */ void -deconstruct_array_builtin(ArrayType *array, +deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp) { @@ -3765,7 +3765,7 @@ deconstruct_array_builtin(ArrayType *array, * if the array *might* contain a null. */ bool -array_contains_nulls(ArrayType *array) +array_contains_nulls(const ArrayType *array) { int nelems; bits8 *bitmap; diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c index 78e19ac39ac..5f7b3114da7 100644 --- a/src/backend/utils/adt/formatting.c +++ b/src/backend/utils/adt/formatting.c @@ -1,4 +1,4 @@ -/* ----------------------------------------------------------------------- +/*------------------------------------------------------------------------- * formatting.c * * src/backend/utils/adt/formatting.c @@ -54,7 +54,7 @@ * than Oracle :-), * to_char('Hello', 'X X X X X') -> 'H e l l o' * - * ----------------------------------------------------------------------- + *------------------------------------------------------------------------- */ #ifdef DEBUG_TO_FROM_CHAR @@ -92,44 +92,46 @@ #include "varatt.h" -/* ---------- +/* * Routines flags - * ---------- */ #define DCH_FLAG 0x1 /* DATE-TIME flag */ #define NUM_FLAG 0x2 /* NUMBER flag */ #define STD_FLAG 0x4 /* STANDARD flag */ -/* ---------- +/* * KeyWord Index (ascii from position 32 (' ') to 126 (~)) - * ---------- */ #define KeyWord_INDEX_SIZE ('~' - ' ') #define KeyWord_INDEX_FILTER(_c) ((_c) <= ' ' || (_c) >= '~' ? 0 : 1) -/* ---------- +/* * Maximal length of one node - * ---------- */ #define DCH_MAX_ITEM_SIZ 12 /* max localized day name */ #define NUM_MAX_ITEM_SIZ 8 /* roman number (RN has 15 chars) */ -/* ---------- +/* * Format parser structs - * ---------- */ + +enum KeySuffixType +{ + SUFFTYPE_PREFIX = 1, + SUFFTYPE_POSTFIX = 2, +}; + typedef struct { const char *name; /* suffix string */ - int len, /* suffix length */ - id, /* used in node->suffix */ - type; /* prefix / postfix */ + size_t len; /* suffix length */ + int id; /* used in node->suffix */ + enum KeySuffixType type; /* prefix / postfix */ } KeySuffix; -/* ---------- +/* * FromCharDateMode - * ---------- * * This value is used to nominate one of several distinct (and mutually * exclusive) date conventions that a keyword can belong to. @@ -144,36 +146,33 @@ typedef enum typedef struct { const char *name; - int len; + size_t len; int id; bool is_digit; FromCharDateMode date_mode; } KeyWord; +enum FormatNodeType +{ + NODE_TYPE_END = 1, + NODE_TYPE_ACTION = 2, + NODE_TYPE_CHAR = 3, + NODE_TYPE_SEPARATOR = 4, + NODE_TYPE_SPACE = 5, +}; + typedef struct { - uint8 type; /* NODE_TYPE_XXX, see below */ + enum FormatNodeType type; char character[MAX_MULTIBYTE_CHAR_LEN + 1]; /* if type is CHAR */ - uint8 suffix; /* keyword prefix/suffix code, if any */ + uint8 suffix; /* keyword prefix/suffix code, if any + * (DCH_SUFFIX_*) */ const KeyWord *key; /* if type is ACTION */ } FormatNode; -#define NODE_TYPE_END 1 -#define NODE_TYPE_ACTION 2 -#define NODE_TYPE_CHAR 3 -#define NODE_TYPE_SEPARATOR 4 -#define NODE_TYPE_SPACE 5 - -#define SUFFTYPE_PREFIX 1 -#define SUFFTYPE_POSTFIX 2 - -#define CLOCK_24_HOUR 0 -#define CLOCK_12_HOUR 1 - -/* ---------- +/* * Full months - * ---------- */ static const char *const months_full[] = { "January", "February", "March", "April", "May", "June", "July", @@ -184,9 +183,9 @@ static const char *const days_short[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", NULL }; -/* ---------- +/* * AD / BC - * ---------- + * * There is no 0 AD. Years go from 1 BC to 1 AD, so we make it * positive and map year == -1 to year zero, and shift all negative * years up one. For interval years, we just return the year. @@ -216,9 +215,8 @@ static const char *const days_short[] = { static const char *const adbc_strings[] = {ad_STR, bc_STR, AD_STR, BC_STR, NULL}; static const char *const adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_STR, NULL}; -/* ---------- +/* * AM / PM - * ---------- */ #define A_M_STR "A.M." #define a_m_STR "a.m." @@ -243,11 +241,10 @@ static const char *const adbc_strings_long[] = {a_d_STR, b_c_STR, A_D_STR, B_C_S static const char *const ampm_strings[] = {am_STR, pm_STR, AM_STR, PM_STR, NULL}; static const char *const ampm_strings_long[] = {a_m_STR, p_m_STR, A_M_STR, P_M_STR, NULL}; -/* ---------- +/* * Months in roman-numeral * (Must be in reverse order for seq_search (in FROM_CHAR), because * 'VIII' must have higher precedence than 'V') - * ---------- */ static const char *const rm_months_upper[] = {"XII", "XI", "X", "IX", "VIII", "VII", "VI", "V", "IV", "III", "II", "I", NULL}; @@ -255,9 +252,8 @@ static const char *const rm_months_upper[] = static const char *const rm_months_lower[] = {"xii", "xi", "x", "ix", "viii", "vii", "vi", "v", "iv", "iii", "ii", "i", NULL}; -/* ---------- +/* * Roman numerals - * ---------- */ static const char *const rm1[] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", NULL}; static const char *const rm10[] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC", NULL}; @@ -289,40 +285,46 @@ static const char *const rm100[] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "D */ #define MAX_ROMAN_LEN 15 -/* ---------- +/* * Ordinal postfixes - * ---------- */ static const char *const numTH[] = {"ST", "ND", "RD", "TH", NULL}; static const char *const numth[] = {"st", "nd", "rd", "th", NULL}; -/* ---------- +/* * Flags & Options: - * ---------- */ -#define TH_UPPER 1 -#define TH_LOWER 2 +enum TH_Case +{ + TH_UPPER = 1, + TH_LOWER = 2, +}; -/* ---------- +enum NUMDesc_lsign +{ + NUM_LSIGN_PRE = -1, + NUM_LSIGN_POST = 1, + NUM_LSIGN_NONE = 0, +}; + +/* * Number description struct - * ---------- */ typedef struct { - int pre, /* (count) numbers before decimal */ - post, /* (count) numbers after decimal */ - lsign, /* want locales sign */ - flag, /* number parameters */ - pre_lsign_num, /* tmp value for lsign */ - multi, /* multiplier for 'V' */ - zero_start, /* position of first zero */ - zero_end, /* position of last zero */ - need_locale; /* needs it locale */ + int pre; /* (count) numbers before decimal */ + int post; /* (count) numbers after decimal */ + enum NUMDesc_lsign lsign; /* want locales sign */ + int flag; /* number parameters (NUM_F_*) */ + int pre_lsign_num; /* tmp value for lsign */ + int multi; /* multiplier for 'V' */ + int zero_start; /* position of first zero */ + int zero_end; /* position of last zero */ + bool need_locale; /* needs it locale */ } NUMDesc; -/* ---------- +/* * Flags for NUMBER version - * ---------- */ #define NUM_F_DECIMAL (1 << 1) #define NUM_F_LDECIMAL (1 << 2) @@ -339,13 +341,8 @@ typedef struct #define NUM_F_MINUS_POST (1 << 13) #define NUM_F_EEEE (1 << 14) -#define NUM_LSIGN_PRE (-1) -#define NUM_LSIGN_POST 1 -#define NUM_LSIGN_NONE 0 - -/* ---------- +/* * Tests - * ---------- */ #define IS_DECIMAL(_f) ((_f)->flag & NUM_F_DECIMAL) #define IS_LDECIMAL(_f) ((_f)->flag & NUM_F_LDECIMAL) @@ -360,7 +357,7 @@ typedef struct #define IS_MULTI(_f) ((_f)->flag & NUM_F_MULTI) #define IS_EEEE(_f) ((_f)->flag & NUM_F_EEEE) -/* ---------- +/* * Format picture cache * * We will cache datetime format pictures up to DCH_CACHE_SIZE bytes long; @@ -376,7 +373,6 @@ typedef struct * * The max number of entries in each cache is DCH_CACHE_ENTRIES * resp. NUM_CACHE_ENTRIES. - * ---------- */ #define DCH_CACHE_OVERHEAD \ MAXALIGN(sizeof(bool) + sizeof(int)) @@ -419,53 +415,49 @@ static NUMCacheEntry *NUMCache[NUM_CACHE_ENTRIES]; static int n_NUMCache = 0; /* current number of entries */ static int NUMCounter = 0; /* aging-event counter */ -/* ---------- +/* * For char->date/time conversion - * ---------- */ typedef struct { FromCharDateMode mode; - int hh, - pm, - mi, - ss, - ssss, - d, /* stored as 1-7, Sunday = 1, 0 means missing */ - dd, - ddd, - mm, - ms, - year, - bc, - ww, - w, - cc, - j, - us, - yysz, /* is it YY or YYYY ? */ - clock, /* 12 or 24 hour clock? */ - tzsign, /* +1, -1, or 0 if no TZH/TZM fields */ - tzh, - tzm, - ff; /* fractional precision */ + int hh; + int pm; + int mi; + int ss; + int ssss; + int d; /* stored as 1-7, Sunday = 1, 0 means missing */ + int dd; + int ddd; + int mm; + int ms; + int year; + int bc; + int ww; + int w; + int cc; + int j; + int us; + int yysz; /* is it YY or YYYY ? */ + bool clock_12_hour; /* 12 or 24 hour clock? */ + int tzsign; /* +1, -1, or 0 if no TZH/TZM fields */ + int tzh; + int tzm; + int ff; /* fractional precision */ bool has_tz; /* was there a TZ field? */ int gmtoffset; /* GMT offset of fixed-offset zone abbrev */ pg_tz *tzp; /* pg_tz for dynamic abbrev */ - char *abbrev; /* dynamic abbrev */ + const char *abbrev; /* dynamic abbrev */ } TmFromChar; -#define ZERO_tmfc(_X) memset(_X, 0, sizeof(TmFromChar)) - struct fmt_tz /* do_to_timestamp's timezone info output */ { bool has_tz; /* was there any TZ/TZH/TZM field? */ int gmtoffset; /* GMT offset in seconds */ }; -/* ---------- +/* * Debug - * ---------- */ #ifdef DEBUG_TO_FROM_CHAR #define DEBUG_TMFC(_X) \ @@ -473,7 +465,7 @@ struct fmt_tz /* do_to_timestamp's timezone info output */ (_X)->mode, (_X)->hh, (_X)->pm, (_X)->mi, (_X)->ss, (_X)->ssss, \ (_X)->d, (_X)->dd, (_X)->ddd, (_X)->mm, (_X)->ms, (_X)->year, \ (_X)->bc, (_X)->ww, (_X)->w, (_X)->cc, (_X)->j, (_X)->us, \ - (_X)->yysz, (_X)->clock) + (_X)->yysz, (_X)->clock_12_hour) #define DEBUG_TM(_X) \ elog(DEBUG_elog_output, "TM:\nsec %d\nyear %d\nmin %d\nwday %d\nhour %d\nyday %d\nmday %d\nnisdst %d\nmon %d\n",\ (_X)->tm_sec, (_X)->tm_year,\ @@ -484,13 +476,12 @@ struct fmt_tz /* do_to_timestamp's timezone info output */ #define DEBUG_TM(_X) #endif -/* ---------- +/* * Datetime to char conversion * * To support intervals as well as timestamps, we use a custom "tm" struct * that is almost like struct pg_tm, but has a 64-bit tm_hour field. * We omit the tm_isdst and tm_zone fields, which are not used here. - * ---------- */ struct fmt_tm { @@ -561,50 +552,74 @@ do { \ * KeyWord definitions *****************************************************************************/ -/* ---------- +/* * Suffixes (FormatNode.suffix is an OR of these codes) - * ---------- */ -#define DCH_S_FM 0x01 -#define DCH_S_TH 0x02 -#define DCH_S_th 0x04 -#define DCH_S_SP 0x08 -#define DCH_S_TM 0x10 +#define DCH_SUFFIX_FM 0x01 +#define DCH_SUFFIX_TH 0x02 +#define DCH_SUFFIX_th 0x04 +#define DCH_SUFFIX_SP 0x08 +#define DCH_SUFFIX_TM 0x10 -/* ---------- +/* * Suffix tests - * ---------- */ -#define S_THth(_s) ((((_s) & DCH_S_TH) || ((_s) & DCH_S_th)) ? 1 : 0) -#define S_TH(_s) (((_s) & DCH_S_TH) ? 1 : 0) -#define S_th(_s) (((_s) & DCH_S_th) ? 1 : 0) -#define S_TH_TYPE(_s) (((_s) & DCH_S_TH) ? TH_UPPER : TH_LOWER) +static inline bool +IS_SUFFIX_TH(uint8 _s) +{ + return (_s & DCH_SUFFIX_TH); +} + +static inline bool +IS_SUFFIX_th(uint8 _s) +{ + return (_s & DCH_SUFFIX_th); +} + +static inline bool +IS_SUFFIX_THth(uint8 _s) +{ + return IS_SUFFIX_TH(_s) || IS_SUFFIX_th(_s); +} + +static inline enum TH_Case +SUFFIX_TH_TYPE(uint8 _s) +{ + return _s & DCH_SUFFIX_TH ? TH_UPPER : TH_LOWER; +} /* Oracle toggles FM behavior, we don't; see docs. */ -#define S_FM(_s) (((_s) & DCH_S_FM) ? 1 : 0) -#define S_SP(_s) (((_s) & DCH_S_SP) ? 1 : 0) -#define S_TM(_s) (((_s) & DCH_S_TM) ? 1 : 0) +static inline bool +IS_SUFFIX_FM(uint8 _s) +{ + return (_s & DCH_SUFFIX_FM); +} + +static inline bool +IS_SUFFIX_TM(uint8 _s) +{ + return (_s & DCH_SUFFIX_TM); +} -/* ---------- +/* * Suffixes definition for DATE-TIME TO/FROM CHAR - * ---------- */ #define TM_SUFFIX_LEN 2 static const KeySuffix DCH_suff[] = { - {"FM", 2, DCH_S_FM, SUFFTYPE_PREFIX}, - {"fm", 2, DCH_S_FM, SUFFTYPE_PREFIX}, - {"TM", TM_SUFFIX_LEN, DCH_S_TM, SUFFTYPE_PREFIX}, - {"tm", 2, DCH_S_TM, SUFFTYPE_PREFIX}, - {"TH", 2, DCH_S_TH, SUFFTYPE_POSTFIX}, - {"th", 2, DCH_S_th, SUFFTYPE_POSTFIX}, - {"SP", 2, DCH_S_SP, SUFFTYPE_POSTFIX}, + {"FM", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX}, + {"fm", 2, DCH_SUFFIX_FM, SUFFTYPE_PREFIX}, + {"TM", TM_SUFFIX_LEN, DCH_SUFFIX_TM, SUFFTYPE_PREFIX}, + {"tm", 2, DCH_SUFFIX_TM, SUFFTYPE_PREFIX}, + {"TH", 2, DCH_SUFFIX_TH, SUFFTYPE_POSTFIX}, + {"th", 2, DCH_SUFFIX_th, SUFFTYPE_POSTFIX}, + {"SP", 2, DCH_SUFFIX_SP, SUFFTYPE_POSTFIX}, /* last */ {NULL, 0, 0, 0} }; -/* ---------- +/* * Format-pictures (KeyWord). * * The KeyWord field; alphabetic sorted, *BUT* strings alike is sorted @@ -628,8 +643,6 @@ static const KeySuffix DCH_suff[] = { * 1) see in index to index['M' - 32], * 2) take keywords position (enum DCH_MI) from index * 3) run sequential search in keywords[] from this position - * - * ---------- */ typedef enum @@ -794,9 +807,8 @@ typedef enum _NUM_last_ } NUM_poz; -/* ---------- +/* * KeyWords for DATE-TIME version - * ---------- */ static const KeyWord DCH_keywords[] = { /* name, len, id, is_digit, date_mode */ @@ -917,11 +929,10 @@ static const KeyWord DCH_keywords[] = { {NULL, 0, 0, 0, 0} }; -/* ---------- +/* * KeyWords for NUMBER version * * The is_digit and date_mode fields are not relevant here. - * ---------- */ static const KeyWord NUM_keywords[] = { /* name, len, id is in Index */ @@ -967,9 +978,8 @@ static const KeyWord NUM_keywords[] = { }; -/* ---------- +/* * KeyWords index for DATE-TIME version - * ---------- */ static const int DCH_index[KeyWord_INDEX_SIZE] = { /* @@ -991,9 +1001,8 @@ static const int DCH_index[KeyWord_INDEX_SIZE] = { /*---- chars over 126 are skipped ----*/ }; -/* ---------- +/* * KeyWords index for NUMBER version - * ---------- */ static const int NUM_index[KeyWord_INDEX_SIZE] = { /* @@ -1015,9 +1024,8 @@ static const int NUM_index[KeyWord_INDEX_SIZE] = { /*---- chars over 126 are skipped ----*/ }; -/* ---------- +/* * Number processor struct - * ---------- */ typedef struct NUMProc { @@ -1062,13 +1070,12 @@ typedef struct NUMProc #define AMOUNT_TEST(s) (Np->inout_p <= Np->inout + (input_len - (s))) -/* ---------- +/* * Functions - * ---------- */ static const KeyWord *index_seq_search(const char *str, const KeyWord *kw, const int *index); -static const KeySuffix *suff_search(const char *str, const KeySuffix *suf, int type); +static const KeySuffix *suff_search(const char *str, const KeySuffix *suf, enum KeySuffixType type); static bool is_separator_char(const char *str); static void NUMDesc_prepare(NUMDesc *num, FormatNode *n); static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, @@ -1084,38 +1091,38 @@ static void dump_index(const KeyWord *k, const int *index); static void dump_node(FormatNode *node, int max); #endif -static const char *get_th(char *num, int type); -static char *str_numth(char *dest, char *num, int type); +static const char *get_th(const char *num, enum TH_Case type); +static char *str_numth(char *dest, const char *num, enum TH_Case type); static int adjust_partial_year_to_2020(int year); -static int strspace_len(const char *str); +static size_t strspace_len(const char *str); static bool from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, Node *escontext); static bool from_char_set_int(int *dest, const int value, const FormatNode *node, Node *escontext); -static int from_char_parse_int_len(int *dest, const char **src, const int len, +static int from_char_parse_int_len(int *dest, const char **src, const size_t len, FormatNode *node, Node *escontext); static int from_char_parse_int(int *dest, const char **src, FormatNode *node, Node *escontext); -static int seq_search_ascii(const char *name, const char *const *array, int *len); -static int seq_search_localized(const char *name, char **array, int *len, +static int seq_search_ascii(const char *name, const char *const *array, size_t *len); +static int seq_search_localized(const char *name, char **array, size_t *len, Oid collid); static bool from_char_seq_search(int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext); -static bool do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, +static bool do_to_timestamp(const text *date_txt, const text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext); -static char *fill_str(char *str, int c, int max); -static FormatNode *NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree); +static void fill_str(char *str, int c, int max); +static FormatNode *NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree); static char *int_to_roman(int number); -static int roman_to_int(NUMProc *Np, int input_len); +static int roman_to_int(NUMProc *Np, size_t input_len); static void NUM_prepare_locale(NUMProc *Np); -static char *get_last_relevant_decnum(char *num); -static void NUM_numpart_from_char(NUMProc *Np, int id, int input_len); +static char *get_last_relevant_decnum(const char *num); +static void NUM_numpart_from_char(NUMProc *Np, int id, size_t input_len); static void NUM_numpart_to_char(NUMProc *Np, int id); static char *NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, - char *number, int input_len, int to_char_out_pre_spaces, + char *number, size_t input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid); static DCHCacheEntry *DCH_cache_getnew(const char *str, bool std); static DCHCacheEntry *DCH_cache_search(const char *str, bool std); @@ -1125,11 +1132,10 @@ static NUMCacheEntry *NUM_cache_search(const char *str); static NUMCacheEntry *NUM_cache_fetch(const char *str); -/* ---------- +/* * Fast sequential search, use index for data selection which * go to seq. cycle (it is very fast for unwanted strings) * (can't be used binary search in format parsing) - * ---------- */ static const KeyWord * index_seq_search(const char *str, const KeyWord *kw, const int *index) @@ -1139,7 +1145,7 @@ index_seq_search(const char *str, const KeyWord *kw, const int *index) if (!KeyWord_INDEX_FILTER(*str)) return NULL; - if ((poz = *(index + (*str - ' '))) > -1) + if ((poz = index[*str - ' ']) > -1) { const KeyWord *k = kw + poz; @@ -1156,11 +1162,9 @@ index_seq_search(const char *str, const KeyWord *kw, const int *index) } static const KeySuffix * -suff_search(const char *str, const KeySuffix *suf, int type) +suff_search(const char *str, const KeySuffix *suf, enum KeySuffixType type) { - const KeySuffix *s; - - for (s = suf; s->name != NULL; s++) + for (const KeySuffix *s = suf; s->name != NULL; s++) { if (s->type != type) continue; @@ -1181,9 +1185,8 @@ is_separator_char(const char *str) !(*str >= '0' && *str <= '9')); } -/* ---------- +/* * Prepare NUMDesc (number description struct) via FormatNode struct - * ---------- */ static void NUMDesc_prepare(NUMDesc *num, FormatNode *n) @@ -1233,7 +1236,7 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) break; case NUM_B: - if (num->pre == 0 && num->post == 0 && (!IS_ZERO(num))) + if (num->pre == 0 && num->post == 0 && !IS_ZERO(num)) num->flag |= NUM_F_BLANK; break; @@ -1364,12 +1367,11 @@ NUMDesc_prepare(NUMDesc *num, FormatNode *n) errdetail("\"RN\" may only be used together with \"FM\"."))); } -/* ---------- +/* * Format parser, search small keywords and keyword's suffixes, and make * format-node tree. * * for DATE-TIME & NUMBER version - * ---------- */ static void parse_format(FormatNode *node, const char *str, const KeyWord *kw, @@ -1514,14 +1516,13 @@ parse_format(FormatNode *node, const char *str, const KeyWord *kw, n->suffix = 0; } -/* ---------- +/* * DEBUG: Dump the FormatNode Tree (debug) - * ---------- */ #ifdef DEBUG_TO_FROM_CHAR -#define DUMP_THth(_suf) (S_TH(_suf) ? "TH" : (S_th(_suf) ? "th" : " ")) -#define DUMP_FM(_suf) (S_FM(_suf) ? "FM" : " ") +#define DUMP_THth(_suf) (IS_SUFFIX_TH(_suf) ? "TH" : (IS_SUFFIX_th(_suf) ? "th" : " ")) +#define DUMP_FM(_suf) (IS_SUFFIX_FM(_suf) ? "FM" : " ") static void dump_node(FormatNode *node, int max) @@ -1554,20 +1555,18 @@ dump_node(FormatNode *node, int max) * Private utils *****************************************************************************/ -/* ---------- +/* * Return ST/ND/RD/TH for simple (1..9) numbers - * type --> 0 upper, 1 lower - * ---------- */ static const char * -get_th(char *num, int type) +get_th(const char *num, enum TH_Case type) { - int len = strlen(num), - last; + size_t len = strlen(num); + char last; Assert(len > 0); - last = *(num + (len - 1)); + last = num[len - 1]; if (!isdigit((unsigned char) last)) ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), @@ -1577,7 +1576,7 @@ get_th(char *num, int type) * All "teens" (<x>1[0-9]) get 'TH/th', while <x>[02-9][123] still get * 'ST/st', 'ND/nd', 'RD/rd', respectively */ - if ((len > 1) && (num[len - 2] == '1')) + if (len > 1 && num[len - 2] == '1') last = 0; switch (last) @@ -1601,13 +1600,11 @@ get_th(char *num, int type) } } -/* ---------- +/* * Convert string-number to ordinal string-number - * type --> 0 upper, 1 lower - * ---------- */ static char * -str_numth(char *dest, char *num, int type) +str_numth(char *dest, const char *num, enum TH_Case type) { if (dest != num) strcpy(dest, num); @@ -1900,14 +1897,13 @@ char * asc_tolower(const char *buff, size_t nbytes) { char *result; - char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); - for (p = result; *p; p++) + for (char *p = result; *p; p++) *p = pg_ascii_tolower((unsigned char) *p); return result; @@ -1923,14 +1919,13 @@ char * asc_toupper(const char *buff, size_t nbytes) { char *result; - char *p; if (!buff) return NULL; result = pnstrdup(buff, nbytes); - for (p = result; *p; p++) + for (char *p = result; *p; p++) *p = pg_ascii_toupper((unsigned char) *p); return result; @@ -1946,7 +1941,6 @@ char * asc_initcap(const char *buff, size_t nbytes) { char *result; - char *p; int wasalnum = false; if (!buff) @@ -1954,7 +1948,7 @@ asc_initcap(const char *buff, size_t nbytes) result = pnstrdup(buff, nbytes); - for (p = result; *p; p++) + for (char *p = result; *p; p++) { char c; @@ -2006,15 +2000,14 @@ asc_toupper_z(const char *buff) /* asc_initcap_z is not currently needed */ -/* ---------- +/* * Skip TM / th in FROM_CHAR * - * If S_THth is on, skip two chars, assuming there are two available - * ---------- + * If IS_SUFFIX_THth is on, skip two chars, assuming there are two available */ #define SKIP_THth(ptr, _suf) \ do { \ - if (S_THth(_suf)) \ + if (IS_SUFFIX_THth(_suf)) \ { \ if (*(ptr)) (ptr) += pg_mblen(ptr); \ if (*(ptr)) (ptr) += pg_mblen(ptr); \ @@ -2023,21 +2016,19 @@ asc_toupper_z(const char *buff) #ifdef DEBUG_TO_FROM_CHAR -/* ----------- +/* * DEBUG: Call for debug and for index checking; (Show ASCII char * and defined keyword for each used position - * ---------- */ static void dump_index(const KeyWord *k, const int *index) { - int i, - count = 0, + int count = 0, free_i = 0; elog(DEBUG_elog_output, "TO-FROM_CHAR: Dump KeyWord Index:"); - for (i = 0; i < KeyWord_INDEX_SIZE; i++) + for (int i = 0; i < KeyWord_INDEX_SIZE; i++) { if (index[i] != -1) { @@ -2055,9 +2046,8 @@ dump_index(const KeyWord *k, const int *index) } #endif /* DEBUG */ -/* ---------- +/* * Return true if next format picture is not digit value - * ---------- */ static bool is_next_separator(FormatNode *n) @@ -2065,7 +2055,7 @@ is_next_separator(FormatNode *n) if (n->type == NODE_TYPE_END) return false; - if (n->type == NODE_TYPE_ACTION && S_THth(n->suffix)) + if (n->type == NODE_TYPE_ACTION && IS_SUFFIX_THth(n->suffix)) return true; /* @@ -2116,10 +2106,10 @@ adjust_partial_year_to_2020(int year) } -static int +static size_t strspace_len(const char *str) { - int len = 0; + size_t len = 0; while (*str && isspace((unsigned char) *str)) { @@ -2150,8 +2140,7 @@ from_char_set_mode(TmFromChar *tmfc, const FromCharDateMode mode, ereturn(escontext, false, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid combination of date conventions"), - errhint("Do not mix Gregorian and ISO week date " - "conventions in a formatting template."))); + errhint("Do not mix Gregorian and ISO week date conventions in a formatting template."))); } return true; } @@ -2174,8 +2163,7 @@ from_char_set_int(int *dest, const int value, const FormatNode *node, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("conflicting values for \"%s\" field in formatting string", node->key->name), - errdetail("This value contradicts a previous setting " - "for the same field type."))); + errdetail("This value contradicts a previous setting for the same field type."))); *dest = value; return true; } @@ -2202,13 +2190,13 @@ from_char_set_int(int *dest, const int value, const FormatNode *node, * with DD and MI). */ static int -from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode *node, +from_char_parse_int_len(int *dest, const char **src, const size_t len, FormatNode *node, Node *escontext) { long result; char copy[DCH_MAX_ITEM_SIZ + 1]; const char *init = *src; - int used; + size_t used; /* * Skip any whitespace before parsing the integer. @@ -2216,9 +2204,9 @@ from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode * *src += strspace_len(*src); Assert(len <= DCH_MAX_ITEM_SIZ); - used = (int) strlcpy(copy, *src, len + 1); + used = strlcpy(copy, *src, len + 1); - if (S_FM(node->suffix) || is_next_separator(node)) + if (IS_SUFFIX_FM(node->suffix) || is_next_separator(node)) { /* * This node is in Fill Mode, or the next node is known to be a @@ -2243,10 +2231,9 @@ from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode * (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("source string too short for \"%s\" formatting field", node->key->name), - errdetail("Field requires %d characters, but only %d remain.", + errdetail("Field requires %zu characters, but only %zu remain.", len, used), - errhint("If your source string is not fixed-width, " - "try using the \"FM\" modifier."))); + errhint("If your source string is not fixed-width, try using the \"FM\" modifier."))); errno = 0; result = strtol(copy, &last, 10); @@ -2257,10 +2244,9 @@ from_char_parse_int_len(int *dest, const char **src, const int len, FormatNode * (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid value \"%s\" for \"%s\"", copy, node->key->name), - errdetail("Field requires %d characters, but only %d could be parsed.", + errdetail("Field requires %zu characters, but only %zu could be parsed.", len, used), - errhint("If your source string is not fixed-width, " - "try using the \"FM\" modifier."))); + errhint("If your source string is not fixed-width, try using the \"FM\" modifier."))); *src += used; } @@ -2317,10 +2303,9 @@ from_char_parse_int(int *dest, const char **src, FormatNode *node, * suitable for comparisons to ASCII strings. */ static int -seq_search_ascii(const char *name, const char *const *array, int *len) +seq_search_ascii(const char *name, const char *const *array, size_t *len) { unsigned char firstc; - const char *const *a; *len = 0; @@ -2331,17 +2316,14 @@ seq_search_ascii(const char *name, const char *const *array, int *len) /* we handle first char specially to gain some speed */ firstc = pg_ascii_tolower((unsigned char) *name); - for (a = array; *a != NULL; a++) + for (const char *const *a = array; *a != NULL; a++) { - const char *p; - const char *n; - /* compare first chars */ if (pg_ascii_tolower((unsigned char) **a) != firstc) continue; /* compare rest of string */ - for (p = *a + 1, n = name + 1;; p++, n++) + for (const char *p = *a + 1, *n = name + 1;; p++, n++) { /* return success if we matched whole array entry */ if (*p == '\0') @@ -2374,9 +2356,8 @@ seq_search_ascii(const char *name, const char *const *array, int *len) * the arrays exported by pg_locale.c aren't const. */ static int -seq_search_localized(const char *name, char **array, int *len, Oid collid) +seq_search_localized(const char *name, char **array, size_t *len, Oid collid) { - char **a; char *upper_name; char *lower_name; @@ -2390,9 +2371,9 @@ seq_search_localized(const char *name, char **array, int *len, Oid collid) * The case-folding processing done below is fairly expensive, so before * doing that, make a quick pass to see if there is an exact match. */ - for (a = array; *a != NULL; a++) + for (char **a = array; *a != NULL; a++) { - int element_len = strlen(*a); + size_t element_len = strlen(*a); if (strncmp(name, *a, element_len) == 0) { @@ -2409,11 +2390,11 @@ seq_search_localized(const char *name, char **array, int *len, Oid collid) lower_name = str_tolower(upper_name, strlen(upper_name), collid); pfree(upper_name); - for (a = array; *a != NULL; a++) + for (char **a = array; *a != NULL; a++) { char *upper_element; char *lower_element; - int element_len; + size_t element_len; /* Likewise upper/lower-case array element */ upper_element = str_toupper(*a, strlen(*a), collid); @@ -2462,7 +2443,7 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, char **localized_array, Oid collid, FormatNode *node, Node *escontext) { - int len; + size_t len; if (localized_array == NULL) *dest = seq_search_ascii(*src, array, &len); @@ -2476,9 +2457,8 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, * any) to avoid including irrelevant data. */ char *copy = pstrdup(*src); - char *c; - for (c = copy; *c; c++) + for (char *c = copy; *c; c++) { if (scanner_isspace(*c)) { @@ -2491,22 +2471,19 @@ from_char_seq_search(int *dest, const char **src, const char *const *array, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid value \"%s\" for \"%s\"", copy, node->key->name), - errdetail("The given value did not match any of " - "the allowed values for this field."))); + errdetail("The given value did not match any of the allowed values for this field."))); } *src += len; return true; } -/* ---------- +/* * Process a TmToChar struct as denoted by a list of FormatNodes. * The formatted data is written to the string pointed to by 'out'. - * ---------- */ static void DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid collid) { - FormatNode *n; char *s; struct fmt_tm *tm = &in->tm; int i; @@ -2515,7 +2492,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col cache_locale_time(); s = out; - for (n = node; n->type != NODE_TYPE_END; n++) + for (FormatNode *n = node; n->type != NODE_TYPE_END; n++) { if (n->type != NODE_TYPE_ACTION) { @@ -2557,40 +2534,40 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col * display time as shown on a 12-hour clock, even for * intervals */ - sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3, + sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3, tm->tm_hour % (HOURS_PER_DAY / 2) == 0 ? (long long) (HOURS_PER_DAY / 2) : (long long) (tm->tm_hour % (HOURS_PER_DAY / 2))); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_HH24: - sprintf(s, "%0*lld", S_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3, + sprintf(s, "%0*lld", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_hour >= 0) ? 2 : 3, (long long) tm->tm_hour); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_MI: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_min >= 0) ? 2 : 3, tm->tm_min); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_SS: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_sec >= 0) ? 2 : 3, tm->tm_sec); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; #define DCH_to_char_fsec(frac_fmt, frac_val) \ sprintf(s, frac_fmt, (int) (frac_val)); \ - if (S_THth(n->suffix)) \ - str_numth(s, s, S_TH_TYPE(n->suffix)); \ + if (IS_SUFFIX_THth(n->suffix)) \ + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); \ s += strlen(s) case DCH_FF1: /* tenth of second */ @@ -2619,8 +2596,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col (long long) (tm->tm_hour * SECS_PER_HOUR + tm->tm_min * SECS_PER_MINUTE + tm->tm_sec)); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_tz: @@ -2660,7 +2637,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; sprintf(s, "%c%0*d", (tm->tm_gmtoff >= 0) ? '+' : '-', - S_FM(n->suffix) ? 0 : 2, + IS_SUFFIX_FM(n->suffix) ? 0 : 2, abs((int) tm->tm_gmtoff) / SECS_PER_HOUR); s += strlen(s); if (abs((int) tm->tm_gmtoff) % SECS_PER_HOUR != 0) @@ -2698,7 +2675,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_toupper_z(localized_full_months[tm->tm_mon - 1], collid); @@ -2710,7 +2687,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, asc_toupper_z(months_full[tm->tm_mon - 1])); s += strlen(s); break; @@ -2718,7 +2695,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_initcap_z(localized_full_months[tm->tm_mon - 1], collid); @@ -2730,7 +2707,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, months_full[tm->tm_mon - 1]); s += strlen(s); break; @@ -2738,7 +2715,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_tolower_z(localized_full_months[tm->tm_mon - 1], collid); @@ -2750,7 +2727,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, asc_tolower_z(months_full[tm->tm_mon - 1])); s += strlen(s); break; @@ -2758,7 +2735,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_toupper_z(localized_abbrev_months[tm->tm_mon - 1], collid); @@ -2777,7 +2754,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_initcap_z(localized_abbrev_months[tm->tm_mon - 1], collid); @@ -2796,7 +2773,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col INVALID_FOR_INTERVAL; if (!tm->tm_mon) break; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_tolower_z(localized_abbrev_months[tm->tm_mon - 1], collid); @@ -2812,15 +2789,15 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col s += strlen(s); break; case DCH_MM: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (tm->tm_mon >= 0) ? 2 : 3, tm->tm_mon); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_DAY: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_toupper_z(localized_full_days[tm->tm_wday], collid); @@ -2832,13 +2809,13 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, asc_toupper_z(days[tm->tm_wday])); s += strlen(s); break; case DCH_Day: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_initcap_z(localized_full_days[tm->tm_wday], collid); @@ -2850,13 +2827,13 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, days[tm->tm_wday]); s += strlen(s); break; case DCH_day: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_tolower_z(localized_full_days[tm->tm_wday], collid); @@ -2868,13 +2845,13 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col errmsg("localized string format value too long"))); } else - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -9, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -9, asc_tolower_z(days[tm->tm_wday])); s += strlen(s); break; case DCH_DY: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_toupper_z(localized_abbrev_days[tm->tm_wday], collid); @@ -2891,7 +2868,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; case DCH_Dy: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_initcap_z(localized_abbrev_days[tm->tm_wday], collid); @@ -2908,7 +2885,7 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; case DCH_dy: INVALID_FOR_INTERVAL; - if (S_TM(n->suffix)) + if (IS_SUFFIX_TM(n->suffix)) { char *str = str_tolower_z(localized_abbrev_days[tm->tm_wday], collid); @@ -2925,54 +2902,54 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col break; case DCH_DDD: case DCH_IDDD: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 3, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 3, (n->key->id == DCH_DDD) ? tm->tm_yday : date2isoyearday(tm->tm_year, tm->tm_mon, tm->tm_mday)); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_DD: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, tm->tm_mday); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, tm->tm_mday); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_D: INVALID_FOR_INTERVAL; sprintf(s, "%d", tm->tm_wday + 1); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_ID: INVALID_FOR_INTERVAL; sprintf(s, "%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_WW: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, (tm->tm_yday - 1) / 7 + 1); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_IW: - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : 2, + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : 2, date2isoweek(tm->tm_year, tm->tm_mon, tm->tm_mday)); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Q: if (!tm->tm_mon) break; sprintf(s, "%d", (tm->tm_mon - 1) / 3 + 1); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_CC: @@ -2988,25 +2965,25 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col i = tm->tm_year / 100 - 1; } if (i <= 99 && i >= -99) - sprintf(s, "%0*d", S_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i); + sprintf(s, "%0*d", IS_SUFFIX_FM(n->suffix) ? 0 : (i >= 0) ? 2 : 3, i); else sprintf(s, "%d", i); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Y_YYY: i = ADJUST_YEAR(tm->tm_year, is_interval) / 1000; sprintf(s, "%d,%03d", i, ADJUST_YEAR(tm->tm_year, is_interval) - (i * 1000)); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YYYY: case DCH_IYYY: sprintf(s, "%0*d", - S_FM(n->suffix) ? 0 : + IS_SUFFIX_FM(n->suffix) ? 0 : (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 4 : 5, (n->key->id == DCH_YYYY ? ADJUST_YEAR(tm->tm_year, is_interval) : @@ -3014,14 +2991,14 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col tm->tm_mon, tm->tm_mday), is_interval))); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YYY: case DCH_IYY: sprintf(s, "%0*d", - S_FM(n->suffix) ? 0 : + IS_SUFFIX_FM(n->suffix) ? 0 : (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 3 : 4, (n->key->id == DCH_YYY ? ADJUST_YEAR(tm->tm_year, is_interval) : @@ -3029,14 +3006,14 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col tm->tm_mon, tm->tm_mday), is_interval)) % 1000); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_YY: case DCH_IY: sprintf(s, "%0*d", - S_FM(n->suffix) ? 0 : + IS_SUFFIX_FM(n->suffix) ? 0 : (ADJUST_YEAR(tm->tm_year, is_interval) >= 0) ? 2 : 3, (n->key->id == DCH_YY ? ADJUST_YEAR(tm->tm_year, is_interval) : @@ -3044,8 +3021,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col tm->tm_mon, tm->tm_mday), is_interval)) % 100); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_Y: @@ -3057,8 +3034,8 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col tm->tm_mon, tm->tm_mday), is_interval)) % 10); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_RM: @@ -3113,21 +3090,21 @@ DCH_to_char(FormatNode *node, bool is_interval, TmToChar *in, char *out, Oid col mon = MONTHS_PER_YEAR - tm->tm_mon; } - sprintf(s, "%*s", S_FM(n->suffix) ? 0 : -4, + sprintf(s, "%*s", IS_SUFFIX_FM(n->suffix) ? 0 : -4, months[mon]); s += strlen(s); } break; case DCH_W: sprintf(s, "%d", (tm->tm_mday - 1) / 7 + 1); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; case DCH_J: sprintf(s, "%d", date2j(tm->tm_year, tm->tm_mon, tm->tm_mday)); - if (S_THth(n->suffix)) - str_numth(s, s, S_TH_TYPE(n->suffix)); + if (IS_SUFFIX_THth(n->suffix)) + str_numth(s, s, SUFFIX_TH_TYPE(n->suffix)); s += strlen(s); break; } @@ -3284,7 +3261,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, return; if (!from_char_set_int(&out->pm, value % 2, n, escontext)) return; - out->clock = CLOCK_12_HOUR; + out->clock_12_hour = true; break; case DCH_AM: case DCH_PM: @@ -3296,13 +3273,13 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, return; if (!from_char_set_int(&out->pm, value % 2, n, escontext)) return; - out->clock = CLOCK_12_HOUR; + out->clock_12_hour = true; break; case DCH_HH: case DCH_HH12: if (from_char_parse_int_len(&out->hh, &s, 2, n, escontext) < 0) return; - out->clock = CLOCK_12_HOUR; + out->clock_12_hour = true; SKIP_THth(s, n->suffix); break; case DCH_HH24: @@ -3389,8 +3366,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, */ ereturn(escontext,, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid value \"%s\" for \"%s\"", - s, n->key->name), + errmsg("invalid value \"%s\" for \"%s\"", s, n->key->name), errdetail("Time zone abbreviation is not recognized."))); } /* otherwise parse it like OF */ @@ -3479,7 +3455,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, case DCH_Month: case DCH_month: if (!from_char_seq_search(&value, &s, months_full, - S_TM(n->suffix) ? localized_full_months : NULL, + IS_SUFFIX_TM(n->suffix) ? localized_full_months : NULL, collid, n, escontext)) return; @@ -3490,7 +3466,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, case DCH_Mon: case DCH_mon: if (!from_char_seq_search(&value, &s, months, - S_TM(n->suffix) ? localized_abbrev_months : NULL, + IS_SUFFIX_TM(n->suffix) ? localized_abbrev_months : NULL, collid, n, escontext)) return; @@ -3506,7 +3482,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, case DCH_Day: case DCH_day: if (!from_char_seq_search(&value, &s, days, - S_TM(n->suffix) ? localized_full_days : NULL, + IS_SUFFIX_TM(n->suffix) ? localized_full_days : NULL, collid, n, escontext)) return; @@ -3518,7 +3494,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, case DCH_Dy: case DCH_dy: if (!from_char_seq_search(&value, &s, days_short, - S_TM(n->suffix) ? localized_abbrev_days : NULL, + IS_SUFFIX_TM(n->suffix) ? localized_abbrev_days : NULL, collid, n, escontext)) return; @@ -3592,8 +3568,7 @@ DCH_from_char(FormatNode *node, const char *in, TmFromChar *out, if (matched < 2) ereturn(escontext,, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("invalid value \"%s\" for \"%s\"", - s, "Y,YYY"))); + errmsg("invalid value \"%s\" for \"%s\"", s, "Y,YYY"))); /* years += (millennia * 1000); */ if (pg_mul_s32_overflow(millennia, 1000, &millennia) || @@ -3725,10 +3700,9 @@ DCH_prevent_counter_overflow(void) static int DCH_datetime_type(FormatNode *node) { - FormatNode *n; int flags = 0; - for (n = node; n->type != NODE_TYPE_END; n++) + for (FormatNode *n = node; n->type != NODE_TYPE_END; n++) { if (n->type != NODE_TYPE_ACTION) continue; @@ -3928,13 +3902,13 @@ DCH_cache_fetch(const char *str, bool std) * for formatting. */ static text * -datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) +datetime_to_char_body(TmToChar *tmtc, const text *fmt, bool is_interval, Oid collid) { FormatNode *format; char *fmt_str, *result; bool incache; - int fmt_len; + size_t fmt_len; text *res; /* @@ -3992,9 +3966,8 @@ datetime_to_char_body(TmToChar *tmtc, text *fmt, bool is_interval, Oid collid) * Public routines ***************************************************************************/ -/* ------------------- +/* * TIMESTAMP to_char() - * ------------------- */ Datum timestamp_to_char(PG_FUNCTION_ARGS) @@ -4068,9 +4041,8 @@ timestamptz_to_char(PG_FUNCTION_ARGS) } -/* ------------------- +/* * INTERVAL to_char() - * ------------------- */ Datum interval_to_char(PG_FUNCTION_ARGS) @@ -4107,12 +4079,11 @@ interval_to_char(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(res); } -/* --------------------- +/* * TO_TIMESTAMP() * * Make Timestamp from date_str which is formatted at argument 'fmt' * ( to_timestamp is reverse to_char() ) - * --------------------- */ Datum to_timestamp(PG_FUNCTION_ARGS) @@ -4148,10 +4119,9 @@ to_timestamp(PG_FUNCTION_ARGS) PG_RETURN_TIMESTAMP(result); } -/* ---------- +/* * TO_DATE * Make Date from date_str which is formatted at argument 'fmt' - * ---------- */ Datum to_date(PG_FUNCTION_ARGS) @@ -4171,8 +4141,7 @@ to_date(PG_FUNCTION_ARGS) if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range: \"%s\"", - text_to_cstring(date_txt)))); + errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; @@ -4180,8 +4149,7 @@ to_date(PG_FUNCTION_ARGS) if (!IS_VALID_DATE(result)) ereport(ERROR, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range: \"%s\"", - text_to_cstring(date_txt)))); + errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); PG_RETURN_DATEADT(result); } @@ -4285,8 +4253,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, if (!IS_VALID_JULIAN(tm.tm_year, tm.tm_mon, tm.tm_mday)) ereturn(escontext, (Datum) 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range: \"%s\"", - text_to_cstring(date_txt)))); + errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); result = date2j(tm.tm_year, tm.tm_mon, tm.tm_mday) - POSTGRES_EPOCH_JDATE; @@ -4295,8 +4262,7 @@ parse_datetime(text *date_txt, text *fmt, Oid collid, bool strict, if (!IS_VALID_DATE(result)) ereturn(escontext, (Datum) 0, (errcode(ERRCODE_DATETIME_VALUE_OUT_OF_RANGE), - errmsg("date out of range: \"%s\"", - text_to_cstring(date_txt)))); + errmsg("date out of range: \"%s\"", text_to_cstring(date_txt)))); *typid = DATEOID; return DateADTGetDatum(result); @@ -4368,7 +4334,7 @@ bool datetime_format_has_tz(const char *fmt_str) { bool incache; - int fmt_len = strlen(fmt_str); + size_t fmt_len = strlen(fmt_str); int result; FormatNode *format; @@ -4428,12 +4394,12 @@ datetime_format_has_tz(const char *fmt_str) * struct 'tm', 'fsec', struct 'tz', and 'fprec'. */ static bool -do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, +do_to_timestamp(const text *date_txt, const text *fmt, Oid collid, bool std, struct pg_tm *tm, fsec_t *fsec, struct fmt_tz *tz, int *fprec, uint32 *flags, Node *escontext) { FormatNode *format = NULL; - TmFromChar tmfc; + TmFromChar tmfc = {0}; int fmt_len; char *date_str; int fmask; @@ -4444,7 +4410,6 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, date_str = text_to_cstring(date_txt); - ZERO_tmfc(&tmfc); ZERO_tm(tm); *fsec = 0; tz->has_tz = false; @@ -4527,14 +4492,13 @@ do_to_timestamp(text *date_txt, text *fmt, Oid collid, bool std, if (tmfc.hh) tm->tm_hour = tmfc.hh; - if (tmfc.clock == CLOCK_12_HOUR) + if (tmfc.clock_12_hour) { if (tm->tm_hour < 1 || tm->tm_hour > HOURS_PER_DAY / 2) { errsave(escontext, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), - errmsg("hour \"%d\" is invalid for the 12-hour clock", - tm->tm_hour), + errmsg("hour \"%d\" is invalid for the 12-hour clock", tm->tm_hour), errhint("Use the 24-hour clock, or give an hour between 1 and 12."))); goto fail; } @@ -4860,27 +4824,17 @@ fail: *********************************************************************/ -static char * +/* + * Fill str with character c max times, and add terminating \0. (So max+1 + * bytes are written altogether!) + */ +static void fill_str(char *str, int c, int max) { memset(str, c, max); - *(str + max) = '\0'; - return str; + str[max] = '\0'; } -#define zeroize_NUM(_n) \ -do { \ - (_n)->flag = 0; \ - (_n)->lsign = 0; \ - (_n)->pre = 0; \ - (_n)->post = 0; \ - (_n)->pre_lsign_num = 0; \ - (_n)->need_locale = 0; \ - (_n)->multi = 0; \ - (_n)->zero_start = 0; \ - (_n)->zero_end = 0; \ -} while(0) - /* This works the same as DCH_prevent_counter_overflow */ static inline void NUM_prevent_counter_overflow(void) @@ -4988,7 +4942,7 @@ NUM_cache_fetch(const char *str) */ ent = NUM_cache_getnew(str); - zeroize_NUM(&ent->Num); + memset(&ent->Num, 0, sizeof ent->Num); parse_format(ent->format, str, NUM_keywords, NULL, NUM_index, NUM_FLAG, &ent->Num); @@ -4998,12 +4952,11 @@ NUM_cache_fetch(const char *str) return ent; } -/* ---------- +/* * Cache routine for NUM to_char version - * ---------- */ static FormatNode * -NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree) +NUM_cache(int len, NUMDesc *Num, const text *pars_str, bool *shouldFree) { FormatNode *format = NULL; char *str; @@ -5020,7 +4973,7 @@ NUM_cache(int len, NUMDesc *Num, text *pars_str, bool *shouldFree) *shouldFree = true; - zeroize_NUM(Num); + memset(Num, 0, sizeof *Num); parse_format(format, str, NUM_keywords, NULL, NUM_index, NUM_FLAG, Num); @@ -5070,8 +5023,7 @@ int_to_roman(int number) { int len, num; - char *p, - *result, + char *result, numstr[12]; result = (char *) palloc(MAX_ROMAN_LEN + 1); @@ -5092,7 +5044,7 @@ int_to_roman(int number) len = snprintf(numstr, sizeof(numstr), "%d", number); Assert(len > 0 && len <= 4); - for (p = numstr; *p != '\0'; p++, --len) + for (char *p = numstr; *p != '\0'; p++, --len) { num = *p - ('0' + 1); if (num < 0) @@ -5126,10 +5078,10 @@ int_to_roman(int number) * If input is invalid, return -1. */ static int -roman_to_int(NUMProc *Np, int input_len) +roman_to_int(NUMProc *Np, size_t input_len) { int result = 0; - int len; + size_t len; char romanChars[MAX_ROMAN_LEN]; int romanValues[MAX_ROMAN_LEN]; int repeatCount = 1; @@ -5168,7 +5120,7 @@ roman_to_int(NUMProc *Np, int input_len) return -1; /* No valid roman numerals. */ /* Check for valid combinations and compute the represented value. */ - for (int i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) { char currChar = romanChars[i]; int currValue = romanValues[i]; @@ -5271,9 +5223,8 @@ roman_to_int(NUMProc *Np, int input_len) } -/* ---------- +/* * Locale - * ---------- */ static void NUM_prepare_locale(NUMProc *Np) @@ -5349,16 +5300,15 @@ NUM_prepare_locale(NUMProc *Np) } } -/* ---------- +/* * Return pointer of last relevant number after decimal point * 12.0500 --> last relevant is '5' * 12.0000 --> last relevant is '.' * If there is no decimal point, return NULL (which will result in same * behavior as if FM hadn't been specified). - * ---------- */ static char * -get_last_relevant_decnum(char *num) +get_last_relevant_decnum(const char *num) { char *result, *p = strchr(num, '.'); @@ -5381,12 +5331,11 @@ get_last_relevant_decnum(char *num) return result; } -/* ---------- +/* * Number extraction for TO_NUMBER() - * ---------- */ static void -NUM_numpart_from_char(NUMProc *Np, int id, int input_len) +NUM_numpart_from_char(NUMProc *Np, int id, size_t input_len) { bool isread = false; @@ -5420,7 +5369,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) */ if (IS_LSIGN(Np->Num) && Np->Num->lsign == NUM_LSIGN_PRE) { - int x = 0; + size_t x = 0; #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read locale pre-sign (%c)", *Np->inout_p); @@ -5499,7 +5448,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) * Np->decimal is always just "." if we don't have a D format token. * So we just unconditionally match to Np->decimal. */ - int x = strlen(Np->decimal); + size_t x = strlen(Np->decimal); #ifdef DEBUG_TO_FROM_CHAR elog(DEBUG_elog_output, "Try read decimal point (%c)", @@ -5538,7 +5487,7 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) (Np->inout_p + 1) < Np->inout + input_len && !isdigit((unsigned char) *(Np->inout_p + 1))) { - int x; + size_t x; char *tmp = Np->inout_p++; #ifdef DEBUG_TO_FROM_CHAR @@ -5596,9 +5545,8 @@ NUM_numpart_from_char(NUMProc *Np, int id, int input_len) *(_n)->number == '0' && \ (_n)->Num->post != 0) -/* ---------- +/* * Add digit or sign to number-string - * ---------- */ static void NUM_numpart_to_char(NUMProc *Np, int id) @@ -5791,7 +5739,7 @@ NUM_numpart_to_char(NUMProc *Np, int id) * Skip over "n" input characters, but only if they aren't numeric data */ static void -NUM_eat_non_data_chars(NUMProc *Np, int n, int input_len) +NUM_eat_non_data_chars(NUMProc *Np, int n, size_t input_len) { while (n-- > 0) { @@ -5805,14 +5753,14 @@ NUM_eat_non_data_chars(NUMProc *Np, int n, int input_len) static char * NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, - char *number, int input_len, int to_char_out_pre_spaces, + char *number, size_t input_len, int to_char_out_pre_spaces, int sign, bool is_to_char, Oid collid) { FormatNode *n; NUMProc _Np, *Np = &_Np; const char *pattern; - int pattern_len; + size_t pattern_len; MemSet(Np, 0, sizeof(NUMProc)); @@ -5893,7 +5841,7 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, */ if (Np->last_relevant && Np->Num->zero_end > Np->out_pre_spaces) { - int last_zero_pos; + size_t last_zero_pos; char *last_zero; /* note that Np->number cannot be zero-length here */ @@ -6267,10 +6215,9 @@ NUM_processor(FormatNode *node, NUMDesc *Num, char *inout, } } -/* ---------- +/* * MACRO: Start part of NUM - for all NUM's to_char variants * (sorry, but I hate copy same code - macro is better..) - * ---------- */ #define NUM_TOCHAR_prepare \ do { \ @@ -6281,13 +6228,12 @@ do { \ format = NUM_cache(len, &Num, fmt, &shouldFree); \ } while (0) -/* ---------- +/* * MACRO: Finish part of NUM - * ---------- */ #define NUM_TOCHAR_finish \ do { \ - int len; \ + size_t len; \ \ NUM_processor(format, &Num, VARDATA(result), numstr, 0, out_pre_spaces, sign, true, PG_GET_COLLATION()); \ \ @@ -6303,9 +6249,8 @@ do { \ SET_VARSIZE(result, len + VARHDRSZ); \ } while (0) -/* ------------------- +/* * NUMERIC to_number() (convert string to numeric) - * ------------------- */ Datum numeric_to_number(PG_FUNCTION_ARGS) @@ -6362,9 +6307,8 @@ numeric_to_number(PG_FUNCTION_ARGS) return result; } -/* ------------------ +/* * NUMERIC to_char() - * ------------------ */ Datum numeric_to_char(PG_FUNCTION_ARGS) @@ -6434,7 +6378,7 @@ numeric_to_char(PG_FUNCTION_ARGS) } else { - int numstr_pre_len; + size_t numstr_pre_len; Numeric val = value; Numeric x; @@ -6490,9 +6434,8 @@ numeric_to_char(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } -/* --------------- +/* * INT4 to_char() - * --------------- */ Datum int4_to_char(PG_FUNCTION_ARGS) @@ -6532,7 +6475,7 @@ int4_to_char(PG_FUNCTION_ARGS) } else { - int numstr_pre_len; + size_t numstr_pre_len; if (IS_MULTI(&Num)) { @@ -6584,9 +6527,8 @@ int4_to_char(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } -/* --------------- +/* * INT8 to_char() - * --------------- */ Datum int8_to_char(PG_FUNCTION_ARGS) @@ -6642,7 +6584,7 @@ int8_to_char(PG_FUNCTION_ARGS) } else { - int numstr_pre_len; + size_t numstr_pre_len; if (IS_MULTI(&Num)) { @@ -6696,9 +6638,8 @@ int8_to_char(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } -/* ----------------- +/* * FLOAT4 to_char() - * ----------------- */ Datum float4_to_char(PG_FUNCTION_ARGS) @@ -6757,7 +6698,7 @@ float4_to_char(PG_FUNCTION_ARGS) { float4 val = value; char *orgnum; - int numstr_pre_len; + size_t numstr_pre_len; if (IS_MULTI(&Num)) { @@ -6809,9 +6750,8 @@ float4_to_char(PG_FUNCTION_ARGS) PG_RETURN_TEXT_P(result); } -/* ----------------- +/* * FLOAT8 to_char() - * ----------------- */ Datum float8_to_char(PG_FUNCTION_ARGS) @@ -6870,7 +6810,7 @@ float8_to_char(PG_FUNCTION_ARGS) { float8 val = value; char *orgnum; - int numstr_pre_len; + size_t numstr_pre_len; if (IS_MULTI(&Num)) { diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c index 14f5cb498fc..88a612b041d 100644 --- a/src/backend/utils/adt/json.c +++ b/src/backend/utils/adt/json.c @@ -89,7 +89,7 @@ typedef struct JsonAggState static void composite_to_json(Datum composite, StringInfo result, bool use_line_feeds); static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, - Datum *vals, bool *nulls, int *valcount, + const Datum *vals, const bool *nulls, int *valcount, JsonTypeCategory tcategory, Oid outfuncoid, bool use_line_feeds); static void array_to_json_internal(Datum array, StringInfo result, @@ -429,8 +429,8 @@ JsonEncodeDateTime(char *buf, Datum value, Oid typid, const int *tzp) * ourselves recursively to process the next dimension. */ static void -array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals, - bool *nulls, int *valcount, JsonTypeCategory tcategory, +array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, const Datum *vals, + const bool *nulls, int *valcount, JsonTypeCategory tcategory, Oid outfuncoid, bool use_line_feeds) { int i; diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index c5e1a027956..41862872e8a 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -477,16 +477,16 @@ static Datum populate_domain(DomainIOData *io, Oid typid, const char *colname, /* functions supporting jsonb_delete, jsonb_set and jsonb_concat */ static JsonbValue *IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, JsonbParseState **state); -static JsonbValue *setPath(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, +static JsonbValue *setPath(JsonbIterator **it, const Datum *path_elems, + const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type); -static void setPathObject(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, +static void setPathObject(JsonbIterator **it, const Datum *path_elems, + const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type); -static void setPathArray(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, JsonbParseState **st, +static void setPathArray(JsonbIterator **it, const Datum *path_elems, + const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type); @@ -1528,7 +1528,7 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) } Datum -jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text) +jsonb_get_element(Jsonb *jb, const Datum *path, int npath, bool *isnull, bool as_text) { JsonbContainer *container = &jb->root; JsonbValue *jbvp = NULL; @@ -1676,7 +1676,7 @@ jsonb_get_element(Jsonb *jb, Datum *path, int npath, bool *isnull, bool as_text) } Datum -jsonb_set_element(Jsonb *jb, Datum *path, int path_len, +jsonb_set_element(Jsonb *jb, const Datum *path, int path_len, JsonbValue *newval) { JsonbValue *res; @@ -1718,8 +1718,8 @@ push_null_elements(JsonbParseState **ps, int num) * Caller is responsible to make sure such path does not exist yet. */ static void -push_path(JsonbParseState **st, int level, Datum *path_elems, - bool *path_nulls, int path_len, JsonbValue *newval) +push_path(JsonbParseState **st, int level, const Datum *path_elems, + const bool *path_nulls, int path_len, JsonbValue *newval) { /* * tpath contains expected type of an empty jsonb created at each level @@ -5201,8 +5201,8 @@ IteratorConcat(JsonbIterator **it1, JsonbIterator **it2, * whatever bits in op_type are set, or nothing is done. */ static JsonbValue * -setPath(JsonbIterator **it, Datum *path_elems, - bool *path_nulls, int path_len, +setPath(JsonbIterator **it, const Datum *path_elems, + const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, int op_type) { JsonbValue v; @@ -5283,7 +5283,7 @@ setPath(JsonbIterator **it, Datum *path_elems, * Object walker for setPath */ static void -setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, +setPathObject(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 npairs, int op_type) { @@ -5422,7 +5422,7 @@ setPathObject(JsonbIterator **it, Datum *path_elems, bool *path_nulls, * Array walker for setPath */ static void -setPathArray(JsonbIterator **it, Datum *path_elems, bool *path_nulls, +setPathArray(JsonbIterator **it, const Datum *path_elems, const bool *path_nulls, int path_len, JsonbParseState **st, int level, JsonbValue *newval, uint32 nelems, int op_type) { diff --git a/src/backend/utils/adt/jsonpath_scan.l b/src/backend/utils/adt/jsonpath_scan.l index c7aab83eeb4..8c3a0a9c642 100644 --- a/src/backend/utils/adt/jsonpath_scan.l +++ b/src/backend/utils/adt/jsonpath_scan.l @@ -574,7 +574,7 @@ hexval(char c, int *result, struct Node *escontext, yyscan_t yyscanner) /* Add given unicode character to scanstring */ static bool -addUnicodeChar(int ch, struct Node *escontext, yyscan_t yyscanner) +addUnicodeChar(char32_t ch, struct Node *escontext, yyscan_t yyscanner) { if (ch == 0) { @@ -607,7 +607,7 @@ addUnicodeChar(int ch, struct Node *escontext, yyscan_t yyscanner) /* Add unicode character, processing any surrogate pairs */ static bool -addUnicode(int ch, int *hi_surrogate, struct Node *escontext, yyscan_t yyscanner) +addUnicode(char32_t ch, int *hi_surrogate, struct Node *escontext, yyscan_t yyscanner) { if (is_utf16_surrogate_first(ch)) { @@ -655,7 +655,7 @@ parseUnicode(char *s, int l, struct Node *escontext, yyscan_t yyscanner) for (i = 2; i < l; i += 2) /* skip '\u' */ { - int ch = 0; + char32_t ch = 0; int j, si; diff --git a/src/backend/utils/adt/multirangetypes_selfuncs.c b/src/backend/utils/adt/multirangetypes_selfuncs.c index b87bcf3ea30..21f0205d803 100644 --- a/src/backend/utils/adt/multirangetypes_selfuncs.c +++ b/src/backend/utils/adt/multirangetypes_selfuncs.c @@ -49,10 +49,10 @@ static float8 get_position(TypeCacheEntry *typcache, const RangeBound *value, static float8 get_len_position(double value, double hist1, double hist2); static float8 get_distance(TypeCacheEntry *typcache, const RangeBound *bound1, const RangeBound *bound2); -static int length_hist_bsearch(Datum *length_hist_values, +static int length_hist_bsearch(const Datum *length_hist_values, int length_hist_nvalues, double value, bool equal); -static double calc_length_hist_frac(Datum *length_hist_values, +static double calc_length_hist_frac(const Datum *length_hist_values, int length_hist_nvalues, double length1, double length2, bool equal); static double calc_hist_selectivity_contained(TypeCacheEntry *typcache, @@ -60,14 +60,14 @@ static double calc_hist_selectivity_contained(TypeCacheEntry *typcache, RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, + const Datum *length_hist_values, int length_hist_nvalues); static double calc_hist_selectivity_contains(TypeCacheEntry *typcache, const RangeBound *lower, const RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, + const Datum *length_hist_values, int length_hist_nvalues); /* @@ -765,7 +765,7 @@ rbound_bsearch(TypeCacheEntry *typcache, const RangeBound *value, const RangeBou * given length, returns -1. */ static int -length_hist_bsearch(Datum *length_hist_values, int length_hist_nvalues, +length_hist_bsearch(const Datum *length_hist_values, int length_hist_nvalues, double value, bool equal) { int lower = -1, @@ -963,7 +963,7 @@ get_distance(TypeCacheEntry *typcache, const RangeBound *bound1, const RangeBoun * 'equal' is true). */ static double -calc_length_hist_frac(Datum *length_hist_values, int length_hist_nvalues, +calc_length_hist_frac(const Datum *length_hist_values, int length_hist_nvalues, double length1, double length2, bool equal) { double frac; @@ -1131,7 +1131,7 @@ static double calc_hist_selectivity_contained(TypeCacheEntry *typcache, const RangeBound *lower, RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues) + const Datum *length_hist_values, int length_hist_nvalues) { int i, upper_index; @@ -1252,7 +1252,7 @@ static double calc_hist_selectivity_contains(TypeCacheEntry *typcache, const RangeBound *lower, const RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues) + const Datum *length_hist_values, int length_hist_nvalues) { int i, lower_index; diff --git a/src/backend/utils/adt/network_selfuncs.c b/src/backend/utils/adt/network_selfuncs.c index 940cdafa546..d08f40e0332 100644 --- a/src/backend/utils/adt/network_selfuncs.c +++ b/src/backend/utils/adt/network_selfuncs.c @@ -48,17 +48,17 @@ static Selectivity networkjoinsel_inner(Oid operator, static Selectivity networkjoinsel_semi(Oid operator, VariableStatData *vardata1, VariableStatData *vardata2); static Selectivity mcv_population(float4 *mcv_numbers, int mcv_nvalues); -static Selectivity inet_hist_value_sel(Datum *values, int nvalues, +static Selectivity inet_hist_value_sel(const Datum *values, int nvalues, Datum constvalue, int opr_codenum); static Selectivity inet_mcv_join_sel(Datum *mcv1_values, float4 *mcv1_numbers, int mcv1_nvalues, Datum *mcv2_values, float4 *mcv2_numbers, int mcv2_nvalues, Oid operator); -static Selectivity inet_mcv_hist_sel(Datum *mcv_values, float4 *mcv_numbers, - int mcv_nvalues, Datum *hist_values, int hist_nvalues, +static Selectivity inet_mcv_hist_sel(const Datum *mcv_values, float4 *mcv_numbers, + int mcv_nvalues, const Datum *hist_values, int hist_nvalues, int opr_codenum); -static Selectivity inet_hist_inclusion_join_sel(Datum *hist1_values, +static Selectivity inet_hist_inclusion_join_sel(const Datum *hist1_values, int hist1_nvalues, - Datum *hist2_values, int hist2_nvalues, + const Datum *hist2_values, int hist2_nvalues, int opr_codenum); static Selectivity inet_semi_join_sel(Datum lhs_value, bool mcv_exists, Datum *mcv_values, int mcv_nvalues, @@ -601,7 +601,7 @@ mcv_population(float4 *mcv_numbers, int mcv_nvalues) * better option than not considering these buckets at all. */ static Selectivity -inet_hist_value_sel(Datum *values, int nvalues, Datum constvalue, +inet_hist_value_sel(const Datum *values, int nvalues, Datum constvalue, int opr_codenum) { Selectivity match = 0.0; @@ -702,8 +702,8 @@ inet_mcv_join_sel(Datum *mcv1_values, float4 *mcv1_numbers, int mcv1_nvalues, * the histogram. */ static Selectivity -inet_mcv_hist_sel(Datum *mcv_values, float4 *mcv_numbers, int mcv_nvalues, - Datum *hist_values, int hist_nvalues, +inet_mcv_hist_sel(const Datum *mcv_values, float4 *mcv_numbers, int mcv_nvalues, + const Datum *hist_values, int hist_nvalues, int opr_codenum) { Selectivity selec = 0.0; @@ -739,8 +739,8 @@ inet_mcv_hist_sel(Datum *mcv_values, float4 *mcv_numbers, int mcv_nvalues, * average? That would at least avoid non-commutative estimation results. */ static Selectivity -inet_hist_inclusion_join_sel(Datum *hist1_values, int hist1_nvalues, - Datum *hist2_values, int hist2_nvalues, +inet_hist_inclusion_join_sel(const Datum *hist1_values, int hist1_nvalues, + const Datum *hist2_values, int hist2_nvalues, int opr_codenum) { double match = 0.0; diff --git a/src/backend/utils/adt/orderedsetaggs.c b/src/backend/utils/adt/orderedsetaggs.c index c41b191be62..2121cc05f28 100644 --- a/src/backend/utils/adt/orderedsetaggs.c +++ b/src/backend/utils/adt/orderedsetaggs.c @@ -660,8 +660,8 @@ pct_info_cmp(const void *pa, const void *pb) */ static struct pct_info * setup_pct_info(int num_percentiles, - Datum *percentiles_datum, - bool *percentiles_null, + const Datum *percentiles_datum, + const bool *percentiles_null, int64 rowcount, bool continuous) { diff --git a/src/backend/utils/adt/pg_locale_builtin.c b/src/backend/utils/adt/pg_locale_builtin.c index 3dc611b50e1..1021e0d129b 100644 --- a/src/backend/utils/adt/pg_locale_builtin.c +++ b/src/backend/utils/adt/pg_locale_builtin.c @@ -15,7 +15,6 @@ #include "catalog/pg_collation.h" #include "common/unicode_case.h" #include "common/unicode_category.h" -#include "mb/pg_wchar.h" #include "miscadmin.h" #include "utils/builtins.h" #include "utils/pg_locale.h" @@ -36,6 +35,23 @@ struct WordBoundaryState }; /* + * In UTF-8, pg_wchar is guaranteed to be the code point value. + */ +static inline char32_t +to_char32(pg_wchar wc) +{ + Assert(GetDatabaseEncoding() == PG_UTF8); + return (char32_t) wc; +} + +static inline pg_wchar +to_pg_wchar(char32_t c32) +{ + Assert(GetDatabaseEncoding() == PG_UTF8); + return (pg_wchar) c32; +} + +/* * Simple word boundary iterator that draws boundaries each time the result of * pg_u_isalnum() changes. */ @@ -47,7 +63,7 @@ initcap_wbnext(void *state) while (wbstate->offset < wbstate->len && wbstate->str[wbstate->offset] != '\0') { - pg_wchar u = utf8_to_unicode((unsigned char *) wbstate->str + + char32_t u = utf8_to_unicode((unsigned char *) wbstate->str + wbstate->offset); bool curr_alnum = pg_u_isalnum(u, wbstate->posix); @@ -112,61 +128,61 @@ strfold_builtin(char *dest, size_t destsize, const char *src, ssize_t srclen, static bool wc_isdigit_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isdigit(wc, !locale->builtin.casemap_full); + return pg_u_isdigit(to_char32(wc), !locale->builtin.casemap_full); } static bool wc_isalpha_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isalpha(wc); + return pg_u_isalpha(to_char32(wc)); } static bool wc_isalnum_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isalnum(wc, !locale->builtin.casemap_full); + return pg_u_isalnum(to_char32(wc), !locale->builtin.casemap_full); } static bool wc_isupper_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isupper(wc); + return pg_u_isupper(to_char32(wc)); } static bool wc_islower_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_islower(wc); + return pg_u_islower(to_char32(wc)); } static bool wc_isgraph_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isgraph(wc); + return pg_u_isgraph(to_char32(wc)); } static bool wc_isprint_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isprint(wc); + return pg_u_isprint(to_char32(wc)); } static bool wc_ispunct_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_ispunct(wc, !locale->builtin.casemap_full); + return pg_u_ispunct(to_char32(wc), !locale->builtin.casemap_full); } static bool wc_isspace_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isspace(wc); + return pg_u_isspace(to_char32(wc)); } static bool wc_isxdigit_builtin(pg_wchar wc, pg_locale_t locale) { - return pg_u_isxdigit(wc, !locale->builtin.casemap_full); + return pg_u_isxdigit(to_char32(wc), !locale->builtin.casemap_full); } static bool @@ -179,13 +195,13 @@ char_is_cased_builtin(char ch, pg_locale_t locale) static pg_wchar wc_toupper_builtin(pg_wchar wc, pg_locale_t locale) { - return unicode_uppercase_simple(wc); + return to_pg_wchar(unicode_uppercase_simple(to_char32(wc))); } static pg_wchar wc_tolower_builtin(pg_wchar wc, pg_locale_t locale) { - return unicode_lowercase_simple(wc); + return to_pg_wchar(unicode_lowercase_simple(to_char32(wc))); } static const struct ctype_methods ctype_methods_builtin = { diff --git a/src/backend/utils/adt/pg_locale_icu.c b/src/backend/utils/adt/pg_locale_icu.c index 05bad202669..f5a0cc8fe41 100644 --- a/src/backend/utils/adt/pg_locale_icu.c +++ b/src/backend/utils/adt/pg_locale_icu.c @@ -128,6 +128,11 @@ char_is_cased_icu(char ch, pg_locale_t locale) (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'); } +/* + * XXX: many of the functions below rely on casts directly from pg_wchar to + * UChar32, which is correct for the UTF-8 encoding, but not in general. + */ + static pg_wchar toupper_icu(pg_wchar wc, pg_locale_t locale) { diff --git a/src/backend/utils/adt/pg_locale_libc.c b/src/backend/utils/adt/pg_locale_libc.c index 7ae778dc296..9c7fcd1fc7a 100644 --- a/src/backend/utils/adt/pg_locale_libc.c +++ b/src/backend/utils/adt/pg_locale_libc.c @@ -45,8 +45,7 @@ * * 2. When working in UTF8 encoding, we use the <wctype.h> functions. * This assumes that every platform uses Unicode codepoints directly - * as the wchar_t representation of Unicode. (XXX: ICU makes this assumption - * even for non-UTF8 encodings, which may be a problem.) On some platforms + * as the wchar_t representation of Unicode. On some platforms * wchar_t is only 16 bits wide, so we have to punt for codepoints > 0xFFFF. * * 3. In all other encodings, we use the <ctype.h> functions for pg_wchar diff --git a/src/backend/utils/adt/pgstatfuncs.c b/src/backend/utils/adt/pgstatfuncs.c index 1fe33df2756..a710508979e 100644 --- a/src/backend/utils/adt/pgstatfuncs.c +++ b/src/backend/utils/adt/pgstatfuncs.c @@ -1637,7 +1637,7 @@ static Datum pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters, TimestampTz stat_reset_timestamp) { -#define PG_STAT_WAL_COLS 5 +#define PG_STAT_WAL_COLS 6 TupleDesc tupdesc; Datum values[PG_STAT_WAL_COLS] = {0}; bool nulls[PG_STAT_WAL_COLS] = {0}; @@ -1651,9 +1651,11 @@ pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters, INT8OID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "wal_bytes", NUMERICOID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_buffers_full", + TupleDescInitEntry(tupdesc, (AttrNumber) 4, "wal_fpi_bytes", + NUMERICOID, -1, 0); + TupleDescInitEntry(tupdesc, (AttrNumber) 5, "wal_buffers_full", INT8OID, -1, 0); - TupleDescInitEntry(tupdesc, (AttrNumber) 5, "stats_reset", + TupleDescInitEntry(tupdesc, (AttrNumber) 6, "stats_reset", TIMESTAMPTZOID, -1, 0); BlessTupleDesc(tupdesc); @@ -1669,12 +1671,18 @@ pg_stat_wal_build_tuple(PgStat_WalCounters wal_counters, ObjectIdGetDatum(0), Int32GetDatum(-1)); - values[3] = Int64GetDatum(wal_counters.wal_buffers_full); + snprintf(buf, sizeof buf, UINT64_FORMAT, wal_counters.wal_fpi_bytes); + values[3] = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + values[4] = Int64GetDatum(wal_counters.wal_buffers_full); if (stat_reset_timestamp != 0) - values[4] = TimestampTzGetDatum(stat_reset_timestamp); + values[5] = TimestampTzGetDatum(stat_reset_timestamp); else - nulls[4] = true; + nulls[5] = true; /* Returns the record as Datum */ PG_RETURN_DATUM(HeapTupleGetDatum(heap_form_tuple(tupdesc, values, nulls))); diff --git a/src/backend/utils/adt/rangetypes_selfuncs.c b/src/backend/utils/adt/rangetypes_selfuncs.c index d126abc5a82..d85252cafb2 100644 --- a/src/backend/utils/adt/rangetypes_selfuncs.c +++ b/src/backend/utils/adt/rangetypes_selfuncs.c @@ -46,18 +46,18 @@ static float8 get_position(TypeCacheEntry *typcache, const RangeBound *value, static float8 get_len_position(double value, double hist1, double hist2); static float8 get_distance(TypeCacheEntry *typcache, const RangeBound *bound1, const RangeBound *bound2); -static int length_hist_bsearch(Datum *length_hist_values, +static int length_hist_bsearch(const Datum *length_hist_values, int length_hist_nvalues, double value, bool equal); -static double calc_length_hist_frac(Datum *length_hist_values, +static double calc_length_hist_frac(const Datum *length_hist_values, int length_hist_nvalues, double length1, double length2, bool equal); static double calc_hist_selectivity_contained(TypeCacheEntry *typcache, const RangeBound *lower, RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues); + const Datum *length_hist_values, int length_hist_nvalues); static double calc_hist_selectivity_contains(TypeCacheEntry *typcache, const RangeBound *lower, const RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues); + const Datum *length_hist_values, int length_hist_nvalues); /* * Returns a default selectivity estimate for given operator, when we don't @@ -654,7 +654,7 @@ rbound_bsearch(TypeCacheEntry *typcache, const RangeBound *value, const RangeBou * given length, returns -1. */ static int -length_hist_bsearch(Datum *length_hist_values, int length_hist_nvalues, +length_hist_bsearch(const Datum *length_hist_values, int length_hist_nvalues, double value, bool equal) { int lower = -1, @@ -852,7 +852,7 @@ get_distance(TypeCacheEntry *typcache, const RangeBound *bound1, const RangeBoun * 'equal' is true). */ static double -calc_length_hist_frac(Datum *length_hist_values, int length_hist_nvalues, +calc_length_hist_frac(const Datum *length_hist_values, int length_hist_nvalues, double length1, double length2, bool equal) { double frac; @@ -1018,7 +1018,7 @@ static double calc_hist_selectivity_contained(TypeCacheEntry *typcache, const RangeBound *lower, RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues) + const Datum *length_hist_values, int length_hist_nvalues) { int i, upper_index; @@ -1139,7 +1139,7 @@ static double calc_hist_selectivity_contains(TypeCacheEntry *typcache, const RangeBound *lower, const RangeBound *upper, const RangeBound *hist_lower, int hist_nvalues, - Datum *length_hist_values, int length_hist_nvalues) + const Datum *length_hist_values, int length_hist_nvalues) { int i, lower_index; diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c index e5e066a5537..cb23ad52782 100644 --- a/src/backend/utils/adt/selfuncs.c +++ b/src/backend/utils/adt/selfuncs.c @@ -6575,6 +6575,13 @@ get_actual_variable_range(PlannerInfo *root, VariableStatData *vardata, continue; /* + * get_actual_variable_endpoint uses the index-only-scan machinery, so + * ignore indexes that can't use it on their first column. + */ + if (!index->canreturn[0]) + continue; + + /* * The first index column must match the desired variable, sortop, and * collation --- but we can use a descending-order index. */ diff --git a/src/backend/utils/adt/tid.c b/src/backend/utils/adt/tid.c index 39dab3e42df..0cfb0bd3735 100644 --- a/src/backend/utils/adt/tid.c +++ b/src/backend/utils/adt/tid.c @@ -42,7 +42,7 @@ #define DELIM ',' #define NTIDARGS 2 -static ItemPointer currtid_for_view(Relation viewrel, ItemPointer tid); +static ItemPointer currtid_for_view(Relation viewrel, const ItemPointerData *tid); /* ---------------------------------------------------------------- * tidin @@ -293,7 +293,7 @@ hashtidextended(PG_FUNCTION_ARGS) * relation "rel". */ static ItemPointer -currtid_internal(Relation rel, ItemPointer tid) +currtid_internal(Relation rel, const ItemPointerData *tid) { ItemPointer result; AclResult aclresult; @@ -335,7 +335,7 @@ currtid_internal(Relation rel, ItemPointer tid) * correspond to the CTID of a base relation. */ static ItemPointer -currtid_for_view(Relation viewrel, ItemPointer tid) +currtid_for_view(Relation viewrel, const ItemPointerData *tid) { TupleDesc att = RelationGetDescr(viewrel); RuleLock *rulelock; diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 0625da9532f..c752cbe5463 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -75,7 +75,7 @@ static bool TS_execute_locations_recurse(QueryItem *curitem, void *arg, TSExecuteCallback chkcond, List **locations); -static int tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len); +static int tsvector_bsearch(const TSVectorData *tsv, char *lexeme, int lexeme_len); static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column); @@ -83,7 +83,7 @@ static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column); * Order: haspos, len, word, for all positions (pos, weight) */ static int -silly_cmp_tsvector(const TSVector a, const TSVector b) +silly_cmp_tsvector(const TSVectorData *a, const TSVectorData *b) { if (VARSIZE(a) < VARSIZE(b)) return -1; @@ -95,8 +95,8 @@ silly_cmp_tsvector(const TSVector a, const TSVector b) return 1; else { - WordEntry *aptr = ARRPTR(a); - WordEntry *bptr = ARRPTR(b); + const WordEntry *aptr = ARRPTR(a); + const WordEntry *bptr = ARRPTR(b); int i = 0; int res; @@ -397,9 +397,9 @@ add_pos(TSVector src, WordEntry *srcptr, * found. */ static int -tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len) +tsvector_bsearch(const TSVectorData *tsv, char *lexeme, int lexeme_len) { - WordEntry *arrin = ARRPTR(tsv); + const WordEntry *arrin = ARRPTR(tsv); int StopLow = 0, StopHigh = tsv->size, StopMiddle, diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 2c398cd9e5c..8d735786e51 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -5419,12 +5419,12 @@ unicode_assigned(PG_FUNCTION_ARGS) ereport(ERROR, (errmsg("Unicode categorization can only be performed if server encoding is UTF8"))); - /* convert to pg_wchar */ + /* convert to char32_t */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); p = (unsigned char *) VARDATA_ANY(input); for (int i = 0; i < size; i++) { - pg_wchar uchar = utf8_to_unicode(p); + char32_t uchar = utf8_to_unicode(p); int category = unicode_category(uchar); if (category == PG_U_UNASSIGNED) @@ -5443,24 +5443,24 @@ unicode_normalize_func(PG_FUNCTION_ARGS) char *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1)); UnicodeNormalizationForm form; int size; - pg_wchar *input_chars; - pg_wchar *output_chars; + char32_t *input_chars; + char32_t *output_chars; unsigned char *p; text *result; int i; form = unicode_norm_form_from_string(formstr); - /* convert to pg_wchar */ + /* convert to char32_t */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); - input_chars = palloc((size + 1) * sizeof(pg_wchar)); + input_chars = palloc((size + 1) * sizeof(char32_t)); p = (unsigned char *) VARDATA_ANY(input); for (i = 0; i < size; i++) { input_chars[i] = utf8_to_unicode(p); p += pg_utf_mblen(p); } - input_chars[i] = (pg_wchar) '\0'; + input_chars[i] = (char32_t) '\0'; Assert((char *) p == VARDATA_ANY(input) + VARSIZE_ANY_EXHDR(input)); /* action */ @@ -5468,7 +5468,7 @@ unicode_normalize_func(PG_FUNCTION_ARGS) /* convert back to UTF-8 string */ size = 0; - for (pg_wchar *wp = output_chars; *wp; wp++) + for (char32_t *wp = output_chars; *wp; wp++) { unsigned char buf[4]; @@ -5480,7 +5480,7 @@ unicode_normalize_func(PG_FUNCTION_ARGS) SET_VARSIZE(result, size + VARHDRSZ); p = (unsigned char *) VARDATA_ANY(result); - for (pg_wchar *wp = output_chars; *wp; wp++) + for (char32_t *wp = output_chars; *wp; wp++) { unicode_to_utf8(*wp, p); p += pg_utf_mblen(p); @@ -5509,8 +5509,8 @@ unicode_is_normalized(PG_FUNCTION_ARGS) char *formstr = text_to_cstring(PG_GETARG_TEXT_PP(1)); UnicodeNormalizationForm form; int size; - pg_wchar *input_chars; - pg_wchar *output_chars; + char32_t *input_chars; + char32_t *output_chars; unsigned char *p; int i; UnicodeNormalizationQC quickcheck; @@ -5519,16 +5519,16 @@ unicode_is_normalized(PG_FUNCTION_ARGS) form = unicode_norm_form_from_string(formstr); - /* convert to pg_wchar */ + /* convert to char32_t */ size = pg_mbstrlen_with_len(VARDATA_ANY(input), VARSIZE_ANY_EXHDR(input)); - input_chars = palloc((size + 1) * sizeof(pg_wchar)); + input_chars = palloc((size + 1) * sizeof(char32_t)); p = (unsigned char *) VARDATA_ANY(input); for (i = 0; i < size; i++) { input_chars[i] = utf8_to_unicode(p); p += pg_utf_mblen(p); } - input_chars[i] = (pg_wchar) '\0'; + input_chars[i] = (char32_t) '\0'; Assert((char *) p == VARDATA_ANY(input) + VARSIZE_ANY_EXHDR(input)); /* quick check (see UAX #15) */ @@ -5542,11 +5542,11 @@ unicode_is_normalized(PG_FUNCTION_ARGS) output_chars = unicode_normalize(form, input_chars); output_size = 0; - for (pg_wchar *wp = output_chars; *wp; wp++) + for (char32_t *wp = output_chars; *wp; wp++) output_size++; result = (size == output_size) && - (memcmp(input_chars, output_chars, size * sizeof(pg_wchar)) == 0); + (memcmp(input_chars, output_chars, size * sizeof(char32_t)) == 0); PG_RETURN_BOOL(result); } @@ -5602,7 +5602,7 @@ unistr(PG_FUNCTION_ARGS) int len; StringInfoData str; text *result; - pg_wchar pair_first = 0; + char16_t pair_first = 0; char cbuf[MAX_UNICODE_EQUIVALENT_STRING + 1]; instr = VARDATA_ANY(input_text); @@ -5626,7 +5626,7 @@ unistr(PG_FUNCTION_ARGS) else if ((len >= 5 && isxdigits_n(instr + 1, 4)) || (len >= 6 && instr[1] == 'u' && isxdigits_n(instr + 2, 4))) { - pg_wchar unicode; + char32_t unicode; int offset = instr[1] == 'u' ? 2 : 1; unicode = hexval_n(instr + offset, 4); @@ -5662,7 +5662,7 @@ unistr(PG_FUNCTION_ARGS) } else if (len >= 8 && instr[1] == '+' && isxdigits_n(instr + 2, 6)) { - pg_wchar unicode; + char32_t unicode; unicode = hexval_n(instr + 2, 6); @@ -5697,7 +5697,7 @@ unistr(PG_FUNCTION_ARGS) } else if (len >= 10 && instr[1] == 'U' && isxdigits_n(instr + 2, 8)) { - pg_wchar unicode; + char32_t unicode; unicode = hexval_n(instr + 2, 8); diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 66b44183695..35c915573a1 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -891,8 +891,8 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent) xmltype * xmlelement(XmlExpr *xexpr, - Datum *named_argvalue, bool *named_argnull, - Datum *argvalue, bool *argnull) + const Datum *named_argvalue, const bool *named_argnull, + const Datum *argvalue, const bool *argnull) { #ifdef USE_LIBXML xmltype *result; diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c index 509d9c6c7b4..30ac1bd91be 100644 --- a/src/backend/utils/cache/catcache.c +++ b/src/backend/utils/cache/catcache.c @@ -117,10 +117,10 @@ static CatCTup *CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, static void ReleaseCatCacheWithOwner(HeapTuple tuple, ResourceOwner resowner); static void ReleaseCatCacheListWithOwner(CatCList *list, ResourceOwner resowner); -static void CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, int *attnos, - Datum *keys); -static void CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, int *attnos, - Datum *srckeys, Datum *dstkeys); +static void CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, const int *attnos, + const Datum *keys); +static void CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, const int *attnos, + const Datum *srckeys, Datum *dstkeys); /* @@ -2279,7 +2279,7 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, Datum *arguments, * Helper routine that frees keys stored in the keys array. */ static void -CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, int *attnos, Datum *keys) +CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, const int *attnos, const Datum *keys) { int i; @@ -2301,8 +2301,8 @@ CatCacheFreeKeys(TupleDesc tupdesc, int nkeys, int *attnos, Datum *keys) * context. */ static void -CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, int *attnos, - Datum *srckeys, Datum *dstkeys) +CatCacheCopyKeys(TupleDesc tupdesc, int nkeys, const int *attnos, + const Datum *srckeys, Datum *dstkeys) { int i; diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index 2b798b823ea..915d0bc9084 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -4658,12 +4658,6 @@ CheckNNConstraintFetch(Relation relation) break; } - check[found].ccenforced = conform->conenforced; - check[found].ccvalid = conform->convalidated; - check[found].ccnoinherit = conform->connoinherit; - check[found].ccname = MemoryContextStrdup(CacheMemoryContext, - NameStr(conform->conname)); - /* Grab and test conbin is actually set */ val = fastgetattr(htup, Anum_pg_constraint_conbin, @@ -4676,7 +4670,13 @@ CheckNNConstraintFetch(Relation relation) /* detoast and convert to cstring in caller's context */ char *s = TextDatumGetCString(val); + check[found].ccenforced = conform->conenforced; + check[found].ccvalid = conform->convalidated; + check[found].ccnoinherit = conform->connoinherit; + check[found].ccname = MemoryContextStrdup(CacheMemoryContext, + NameStr(conform->conname)); check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s); + pfree(s); found++; } diff --git a/src/backend/utils/mb/mbutils.c b/src/backend/utils/mb/mbutils.c index 886ecbad871..fb629ed5c8f 100644 --- a/src/backend/utils/mb/mbutils.c +++ b/src/backend/utils/mb/mbutils.c @@ -862,7 +862,7 @@ perform_default_encoding_conversion(const char *src, int len, * may call this outside any transaction, or in an aborted transaction. */ void -pg_unicode_to_server(pg_wchar c, unsigned char *s) +pg_unicode_to_server(char32_t c, unsigned char *s) { unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1]; int c_as_utf8_len; @@ -924,7 +924,7 @@ pg_unicode_to_server(pg_wchar c, unsigned char *s) * but simply return false on conversion failure. */ bool -pg_unicode_to_server_noerror(pg_wchar c, unsigned char *s) +pg_unicode_to_server_noerror(char32_t c, unsigned char *s) { unsigned char c_as_utf8[MAX_MULTIBYTE_CHAR_LEN + 1]; int c_as_utf8_len; diff --git a/src/backend/utils/misc/gen_guc_tables.pl b/src/backend/utils/misc/gen_guc_tables.pl index b187259bf1e..3efde02bab8 100644 --- a/src/backend/utils/misc/gen_guc_tables.pl +++ b/src/backend/utils/misc/gen_guc_tables.pl @@ -25,10 +25,7 @@ my $parse = Catalog::ParseData($input_fname); open my $ofh, '>', $output_fname or die; print_boilerplate($ofh, $output_fname, 'GUC tables'); -foreach my $type (qw(bool int real string enum)) -{ - print_one_table($ofh, $type); -} +print_table($ofh); close $ofh; @@ -41,56 +38,52 @@ sub dquote return q{"} . $s =~ s/"/\\"/gr . q{"}; } -# Print GUC table for one type. -sub print_one_table +# Print GUC table. +sub print_table { - my ($ofh, $type) = @_; - my $Type = ucfirst $type; + my ($ofh) = @_; print $ofh "\n\n"; - print $ofh "struct config_${type} ConfigureNames${Type}[] =\n"; + print $ofh "struct config_generic ConfigureNames[] =\n"; print $ofh "{\n"; foreach my $entry (@{$parse}) { - next if $entry->{type} ne $type; - print $ofh "#ifdef $entry->{ifdef}\n" if $entry->{ifdef}; print $ofh "\t{\n"; - print $ofh "\t\t{\n"; - printf $ofh "\t\t\t.name = %s,\n", dquote($entry->{name}); - printf $ofh "\t\t\t.context = %s,\n", $entry->{context}; - printf $ofh "\t\t\t.group = %s,\n", $entry->{group}; - printf $ofh "\t\t\t.short_desc = gettext_noop(%s),\n", + printf $ofh "\t\t.name = %s,\n", dquote($entry->{name}); + printf $ofh "\t\t.context = %s,\n", $entry->{context}; + printf $ofh "\t\t.group = %s,\n", $entry->{group}; + printf $ofh "\t\t.short_desc = gettext_noop(%s),\n", dquote($entry->{short_desc}); - printf $ofh "\t\t\t.long_desc = gettext_noop(%s),\n", + printf $ofh "\t\t.long_desc = gettext_noop(%s),\n", dquote($entry->{long_desc}) if $entry->{long_desc}; - printf $ofh "\t\t\t.flags = %s,\n", $entry->{flags} - if $entry->{flags}; - printf $ofh "\t\t\t.vartype = %s,\n", ('PGC_' . uc($type)); - print $ofh "\t\t},\n"; - printf $ofh "\t\t.variable = &%s,\n", $entry->{variable}; - printf $ofh "\t\t.boot_val = %s,\n", $entry->{boot_val}; - printf $ofh "\t\t.min = %s,\n", $entry->{min} + printf $ofh "\t\t.flags = %s,\n", $entry->{flags} if $entry->{flags}; + printf $ofh "\t\t.vartype = %s,\n", ('PGC_' . uc($entry->{type})); + printf $ofh "\t\t._%s = {\n", $entry->{type}; + printf $ofh "\t\t\t.variable = &%s,\n", $entry->{variable}; + printf $ofh "\t\t\t.boot_val = %s,\n", $entry->{boot_val}; + printf $ofh "\t\t\t.min = %s,\n", $entry->{min} if $entry->{type} eq 'int' || $entry->{type} eq 'real'; - printf $ofh "\t\t.max = %s,\n", $entry->{max} + printf $ofh "\t\t\t.max = %s,\n", $entry->{max} if $entry->{type} eq 'int' || $entry->{type} eq 'real'; - printf $ofh "\t\t.options = %s,\n", $entry->{options} + printf $ofh "\t\t\t.options = %s,\n", $entry->{options} if $entry->{type} eq 'enum'; - printf $ofh "\t\t.check_hook = %s,\n", $entry->{check_hook} + printf $ofh "\t\t\t.check_hook = %s,\n", $entry->{check_hook} if $entry->{check_hook}; - printf $ofh "\t\t.assign_hook = %s,\n", $entry->{assign_hook} + printf $ofh "\t\t\t.assign_hook = %s,\n", $entry->{assign_hook} if $entry->{assign_hook}; - printf $ofh "\t\t.show_hook = %s,\n", $entry->{show_hook} + printf $ofh "\t\t\t.show_hook = %s,\n", $entry->{show_hook} if $entry->{show_hook}; + print $ofh "\t\t},\n"; print $ofh "\t},\n"; print $ofh "#endif\n" if $entry->{ifdef}; print $ofh "\n"; } print $ofh "\t/* End-of-list marker */\n"; - print $ofh "\t{{0}}\n"; + print $ofh "\t{0}\n"; print $ofh "};\n"; return; diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index a82286cc98a..679846da42c 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -245,12 +245,12 @@ static void ReportGUCOption(struct config_generic *record); static void set_config_sourcefile(const char *name, char *sourcefile, int sourceline); static void reapply_stacked_values(struct config_generic *variable, - struct config_string *pHolder, + struct config_generic *pHolder, GucStack *stack, const char *curvalue, GucContext curscontext, GucSource cursource, Oid cursrole); -static void free_placeholder(struct config_string *pHolder); +static void free_placeholder(struct config_generic *pHolder); static bool validate_option_array_item(const char *name, const char *value, bool skipIfNoPermissions); static void write_auto_conf_file(int fd, const char *filename, ConfigVariable *head); @@ -261,15 +261,15 @@ static bool assignable_custom_variable_name(const char *name, bool skip_errors, int elevel); static void do_serialize(char **destptr, Size *maxbytes, const char *fmt,...) pg_attribute_printf(3, 4); -static bool call_bool_check_hook(const struct config_bool *conf, bool *newval, +static bool call_bool_check_hook(const struct config_generic *conf, bool *newval, void **extra, GucSource source, int elevel); -static bool call_int_check_hook(const struct config_int *conf, int *newval, +static bool call_int_check_hook(const struct config_generic *conf, int *newval, void **extra, GucSource source, int elevel); -static bool call_real_check_hook(const struct config_real *conf, double *newval, +static bool call_real_check_hook(const struct config_generic *conf, double *newval, void **extra, GucSource source, int elevel); -static bool call_string_check_hook(const struct config_string *conf, char **newval, +static bool call_string_check_hook(const struct config_generic *conf, char **newval, void **extra, GucSource source, int elevel); -static bool call_enum_check_hook(const struct config_enum *conf, int *newval, +static bool call_enum_check_hook(const struct config_generic *conf, int *newval, void **extra, GucSource source, int elevel); @@ -703,13 +703,13 @@ guc_free(void *ptr) * Detect whether strval is referenced anywhere in a GUC string item */ static bool -string_field_used(struct config_string *conf, char *strval) +string_field_used(struct config_generic *conf, char *strval) { - if (strval == *(conf->variable) || - strval == conf->reset_val || - strval == conf->boot_val) + if (strval == *(conf->_string.variable) || + strval == conf->_string.reset_val || + strval == conf->_string.boot_val) return true; - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = conf->stack; stack; stack = stack->prev) { if (strval == stack->prior.val.stringval || strval == stack->masked.val.stringval) @@ -724,7 +724,7 @@ string_field_used(struct config_string *conf, char *strval) * states). */ static void -set_string_field(struct config_string *conf, char **field, char *newval) +set_string_field(struct config_generic *conf, char **field, char *newval) { char *oldval = *field; @@ -787,25 +787,19 @@ set_stack_value(struct config_generic *gconf, config_var_value *val) switch (gconf->vartype) { case PGC_BOOL: - val->val.boolval = - *((struct config_bool *) gconf)->variable; + val->val.boolval = *gconf->_bool.variable; break; case PGC_INT: - val->val.intval = - *((struct config_int *) gconf)->variable; + val->val.intval = *gconf->_int.variable; break; case PGC_REAL: - val->val.realval = - *((struct config_real *) gconf)->variable; + val->val.realval = *gconf->_real.variable; break; case PGC_STRING: - set_string_field((struct config_string *) gconf, - &(val->val.stringval), - *((struct config_string *) gconf)->variable); + set_string_field(gconf, &(val->val.stringval), *gconf->_string.variable); break; case PGC_ENUM: - val->val.enumval = - *((struct config_enum *) gconf)->variable; + val->val.enumval = *gconf->_enum.variable; break; } set_extra_field(gconf, &(val->extra), gconf->extra); @@ -827,7 +821,7 @@ discard_stack_value(struct config_generic *gconf, config_var_value *val) /* no need to do anything */ break; case PGC_STRING: - set_string_field((struct config_string *) gconf, + set_string_field(gconf, &(val->val.stringval), NULL); break; @@ -892,19 +886,7 @@ build_guc_variables(void) /* * Count all the built-in variables. */ - for (int i = 0; ConfigureNamesBool[i].gen.name; i++) - num_vars++; - - for (int i = 0; ConfigureNamesInt[i].gen.name; i++) - num_vars++; - - for (int i = 0; ConfigureNamesReal[i].gen.name; i++) - num_vars++; - - for (int i = 0; ConfigureNamesString[i].gen.name; i++) - num_vars++; - - for (int i = 0; ConfigureNamesEnum[i].gen.name; i++) + for (int i = 0; ConfigureNames[i].name; i++) num_vars++; /* @@ -922,57 +904,9 @@ build_guc_variables(void) &hash_ctl, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT); - for (int i = 0; ConfigureNamesBool[i].gen.name; i++) - { - struct config_generic *gucvar = &ConfigureNamesBool[i].gen; - - hentry = (GUCHashEntry *) hash_search(guc_hashtab, - &gucvar->name, - HASH_ENTER, - &found); - Assert(!found); - hentry->gucvar = gucvar; - } - - for (int i = 0; ConfigureNamesInt[i].gen.name; i++) - { - struct config_generic *gucvar = &ConfigureNamesInt[i].gen; - - hentry = (GUCHashEntry *) hash_search(guc_hashtab, - &gucvar->name, - HASH_ENTER, - &found); - Assert(!found); - hentry->gucvar = gucvar; - } - - for (int i = 0; ConfigureNamesReal[i].gen.name; i++) - { - struct config_generic *gucvar = &ConfigureNamesReal[i].gen; - - hentry = (GUCHashEntry *) hash_search(guc_hashtab, - &gucvar->name, - HASH_ENTER, - &found); - Assert(!found); - hentry->gucvar = gucvar; - } - - for (int i = 0; ConfigureNamesString[i].gen.name; i++) - { - struct config_generic *gucvar = &ConfigureNamesString[i].gen; - - hentry = (GUCHashEntry *) hash_search(guc_hashtab, - &gucvar->name, - HASH_ENTER, - &found); - Assert(!found); - hentry->gucvar = gucvar; - } - - for (int i = 0; ConfigureNamesEnum[i].gen.name; i++) + for (int i = 0; ConfigureNames[i].name; i++) { - struct config_generic *gucvar = &ConfigureNamesEnum[i].gen; + struct config_generic *gucvar = &ConfigureNames[i]; hentry = (GUCHashEntry *) hash_search(guc_hashtab, &gucvar->name, @@ -1122,44 +1056,42 @@ assignable_custom_variable_name(const char *name, bool skip_errors, int elevel) static struct config_generic * add_placeholder_variable(const char *name, int elevel) { - size_t sz = sizeof(struct config_string) + sizeof(char *); - struct config_string *var; - struct config_generic *gen; + size_t sz = sizeof(struct config_generic) + sizeof(char *); + struct config_generic *var; - var = (struct config_string *) guc_malloc(elevel, sz); + var = (struct config_generic *) guc_malloc(elevel, sz); if (var == NULL) return NULL; memset(var, 0, sz); - gen = &var->gen; - gen->name = guc_strdup(elevel, name); - if (gen->name == NULL) + var->name = guc_strdup(elevel, name); + if (var->name == NULL) { guc_free(var); return NULL; } - gen->context = PGC_USERSET; - gen->group = CUSTOM_OPTIONS; - gen->short_desc = "GUC placeholder variable"; - gen->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER; - gen->vartype = PGC_STRING; + var->context = PGC_USERSET; + var->group = CUSTOM_OPTIONS; + var->short_desc = "GUC placeholder variable"; + var->flags = GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_CUSTOM_PLACEHOLDER; + var->vartype = PGC_STRING; /* * The char* is allocated at the end of the struct since we have no * 'static' place to point to. Note that the current value, as well as * the boot and reset values, start out NULL. */ - var->variable = (char **) (var + 1); + var->_string.variable = (char **) (var + 1); - if (!add_guc_variable((struct config_generic *) var, elevel)) + if (!add_guc_variable(var, elevel)) { - guc_free(unconstify(char *, gen->name)); + guc_free(unconstify(char *, var->name)); guc_free(var); return NULL; } - return gen; + return var; } /* @@ -1385,62 +1317,62 @@ check_GUC_init(const struct config_generic *gconf) { case PGC_BOOL: { - const struct config_bool *conf = (const struct config_bool *) gconf; + const struct config_bool *conf = &gconf->_bool; if (*conf->variable && !conf->boot_val) { elog(LOG, "GUC (PGC_BOOL) %s, boot_val=%d, C-var=%d", - conf->gen.name, conf->boot_val, *conf->variable); + gconf->name, conf->boot_val, *conf->variable); return false; } break; } case PGC_INT: { - const struct config_int *conf = (const struct config_int *) gconf; + const struct config_int *conf = &gconf->_int; if (*conf->variable != 0 && *conf->variable != conf->boot_val) { elog(LOG, "GUC (PGC_INT) %s, boot_val=%d, C-var=%d", - conf->gen.name, conf->boot_val, *conf->variable); + gconf->name, conf->boot_val, *conf->variable); return false; } break; } case PGC_REAL: { - const struct config_real *conf = (const struct config_real *) gconf; + const struct config_real *conf = &gconf->_real; if (*conf->variable != 0.0 && *conf->variable != conf->boot_val) { elog(LOG, "GUC (PGC_REAL) %s, boot_val=%g, C-var=%g", - conf->gen.name, conf->boot_val, *conf->variable); + gconf->name, conf->boot_val, *conf->variable); return false; } break; } case PGC_STRING: { - const struct config_string *conf = (const struct config_string *) gconf; + const struct config_string *conf = &gconf->_string; if (*conf->variable != NULL && (conf->boot_val == NULL || strcmp(*conf->variable, conf->boot_val) != 0)) { elog(LOG, "GUC (PGC_STRING) %s, boot_val=%s, C-var=%s", - conf->gen.name, conf->boot_val ? conf->boot_val : "<null>", *conf->variable); + gconf->name, conf->boot_val ? conf->boot_val : "<null>", *conf->variable); return false; } break; } case PGC_ENUM: { - const struct config_enum *conf = (const struct config_enum *) gconf; + const struct config_enum *conf = &gconf->_enum; if (*conf->variable != conf->boot_val) { elog(LOG, "GUC (PGC_ENUM) %s, boot_val=%d, C-var=%d", - conf->gen.name, conf->boot_val, *conf->variable); + gconf->name, conf->boot_val, *conf->variable); return false; } break; @@ -1607,13 +1539,13 @@ InitializeOneGUCOption(struct config_generic *gconf) { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) gconf; + struct config_bool *conf = &gconf->_bool; bool newval = conf->boot_val; - if (!call_bool_check_hook(conf, &newval, &extra, + if (!call_bool_check_hook(gconf, &newval, &extra, PGC_S_DEFAULT, LOG)) elog(FATAL, "failed to initialize %s to %d", - conf->gen.name, (int) newval); + gconf->name, (int) newval); if (conf->assign_hook) conf->assign_hook(newval, extra); *conf->variable = conf->reset_val = newval; @@ -1621,15 +1553,15 @@ InitializeOneGUCOption(struct config_generic *gconf) } case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; int newval = conf->boot_val; Assert(newval >= conf->min); Assert(newval <= conf->max); - if (!call_int_check_hook(conf, &newval, &extra, + if (!call_int_check_hook(gconf, &newval, &extra, PGC_S_DEFAULT, LOG)) elog(FATAL, "failed to initialize %s to %d", - conf->gen.name, newval); + gconf->name, newval); if (conf->assign_hook) conf->assign_hook(newval, extra); *conf->variable = conf->reset_val = newval; @@ -1637,15 +1569,15 @@ InitializeOneGUCOption(struct config_generic *gconf) } case PGC_REAL: { - struct config_real *conf = (struct config_real *) gconf; + struct config_real *conf = &gconf->_real; double newval = conf->boot_val; Assert(newval >= conf->min); Assert(newval <= conf->max); - if (!call_real_check_hook(conf, &newval, &extra, + if (!call_real_check_hook(gconf, &newval, &extra, PGC_S_DEFAULT, LOG)) elog(FATAL, "failed to initialize %s to %g", - conf->gen.name, newval); + gconf->name, newval); if (conf->assign_hook) conf->assign_hook(newval, extra); *conf->variable = conf->reset_val = newval; @@ -1653,7 +1585,7 @@ InitializeOneGUCOption(struct config_generic *gconf) } case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; char *newval; /* non-NULL boot_val must always get strdup'd */ @@ -1662,10 +1594,10 @@ InitializeOneGUCOption(struct config_generic *gconf) else newval = NULL; - if (!call_string_check_hook(conf, &newval, &extra, + if (!call_string_check_hook(gconf, &newval, &extra, PGC_S_DEFAULT, LOG)) elog(FATAL, "failed to initialize %s to \"%s\"", - conf->gen.name, newval ? newval : ""); + gconf->name, newval ? newval : ""); if (conf->assign_hook) conf->assign_hook(newval, extra); *conf->variable = conf->reset_val = newval; @@ -1673,13 +1605,13 @@ InitializeOneGUCOption(struct config_generic *gconf) } case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; int newval = conf->boot_val; - if (!call_enum_check_hook(conf, &newval, &extra, + if (!call_enum_check_hook(gconf, &newval, &extra, PGC_S_DEFAULT, LOG)) elog(FATAL, "failed to initialize %s to %d", - conf->gen.name, newval); + gconf->name, newval); if (conf->assign_hook) conf->assign_hook(newval, extra); *conf->variable = conf->reset_val = newval; @@ -1726,7 +1658,7 @@ SelectConfigFiles(const char *userDoption, const char *progname) char *fname; bool fname_is_malloced; struct stat stat_buf; - struct config_string *data_directory_rec; + struct config_generic *data_directory_rec; /* configdir is -D option, or $PGDATA if no -D */ if (userDoption) @@ -1806,10 +1738,10 @@ SelectConfigFiles(const char *userDoption, const char *progname) * Note: SetDataDir will copy and absolute-ize its argument, so we don't * have to. */ - data_directory_rec = (struct config_string *) + data_directory_rec = find_option("data_directory", false, false, PANIC); - if (*data_directory_rec->variable) - SetDataDir(*data_directory_rec->variable); + if (*data_directory_rec->_string.variable) + SetDataDir(*data_directory_rec->_string.variable); else if (configdir) SetDataDir(configdir); else @@ -1971,62 +1903,62 @@ ResetAllOptions(void) { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) gconf; + struct config_bool *conf = &gconf->_bool; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->gen.reset_extra); + gconf->reset_extra); *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->gen.reset_extra); + set_extra_field(gconf, &gconf->extra, + gconf->reset_extra); break; } case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->gen.reset_extra); + gconf->reset_extra); *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->gen.reset_extra); + set_extra_field(gconf, &gconf->extra, + gconf->reset_extra); break; } case PGC_REAL: { - struct config_real *conf = (struct config_real *) gconf; + struct config_real *conf = &gconf->_real; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->gen.reset_extra); + gconf->reset_extra); *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->gen.reset_extra); + set_extra_field(gconf, &gconf->extra, + gconf->reset_extra); break; } case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->gen.reset_extra); - set_string_field(conf, conf->variable, conf->reset_val); - set_extra_field(&conf->gen, &conf->gen.extra, - conf->gen.reset_extra); + gconf->reset_extra); + set_string_field(gconf, conf->variable, conf->reset_val); + set_extra_field(gconf, &gconf->extra, + gconf->reset_extra); break; } case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; if (conf->assign_hook) conf->assign_hook(conf->reset_val, - conf->gen.reset_extra); + gconf->reset_extra); *conf->variable = conf->reset_val; - set_extra_field(&conf->gen, &conf->gen.extra, - conf->gen.reset_extra); + set_extra_field(gconf, &gconf->extra, + gconf->reset_extra); break; } } @@ -2346,17 +2278,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) gconf; + struct config_bool *conf = &gconf->_bool; bool newval = newvalue.val.boolval; void *newextra = newvalue.extra; if (*conf->variable != newval || - conf->gen.extra != newextra) + gconf->extra != newextra) { if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(gconf, &gconf->extra, newextra); changed = true; } @@ -2364,17 +2296,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) } case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; int newval = newvalue.val.intval; void *newextra = newvalue.extra; if (*conf->variable != newval || - conf->gen.extra != newextra) + gconf->extra != newextra) { if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(gconf, &gconf->extra, newextra); changed = true; } @@ -2382,17 +2314,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) } case PGC_REAL: { - struct config_real *conf = (struct config_real *) gconf; + struct config_real *conf = &gconf->_real; double newval = newvalue.val.realval; void *newextra = newvalue.extra; if (*conf->variable != newval || - conf->gen.extra != newextra) + gconf->extra != newextra) { if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(gconf, &gconf->extra, newextra); changed = true; } @@ -2400,17 +2332,17 @@ AtEOXact_GUC(bool isCommit, int nestLevel) } case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; char *newval = newvalue.val.stringval; void *newextra = newvalue.extra; if (*conf->variable != newval || - conf->gen.extra != newextra) + gconf->extra != newextra) { if (conf->assign_hook) conf->assign_hook(newval, newextra); - set_string_field(conf, conf->variable, newval); - set_extra_field(&conf->gen, &conf->gen.extra, + set_string_field(gconf, conf->variable, newval); + set_extra_field(gconf, &gconf->extra, newextra); changed = true; } @@ -2421,23 +2353,23 @@ AtEOXact_GUC(bool isCommit, int nestLevel) * we have type-specific code anyway, might as * well inline it. */ - set_string_field(conf, &stack->prior.val.stringval, NULL); - set_string_field(conf, &stack->masked.val.stringval, NULL); + set_string_field(gconf, &stack->prior.val.stringval, NULL); + set_string_field(gconf, &stack->masked.val.stringval, NULL); break; } case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; int newval = newvalue.val.enumval; void *newextra = newvalue.extra; if (*conf->variable != newval || - conf->gen.extra != newextra) + gconf->extra != newextra) { if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(gconf, &gconf->extra, newextra); changed = true; } @@ -2960,16 +2892,16 @@ parse_real(const char *value, double *result, int flags, const char **hintmsg) * allocated for modification. */ const char * -config_enum_lookup_by_value(const struct config_enum *record, int val) +config_enum_lookup_by_value(const struct config_generic *record, int val) { - for (const struct config_enum_entry *entry = record->options; entry && entry->name; entry++) + for (const struct config_enum_entry *entry = record->_enum.options; entry && entry->name; entry++) { if (entry->val == val) return entry->name; } elog(ERROR, "could not find enum option %d for %s", - val, record->gen.name); + val, record->name); return NULL; /* silence compiler */ } @@ -3070,41 +3002,39 @@ parse_and_validate_value(const struct config_generic *record, { case PGC_BOOL: { - const struct config_bool *conf = (const struct config_bool *) record; - if (!parse_bool(value, &newval->boolval)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("parameter \"%s\" requires a Boolean value", - conf->gen.name))); + record->name))); return false; } - if (!call_bool_check_hook(conf, &newval->boolval, newextra, + if (!call_bool_check_hook(record, &newval->boolval, newextra, source, elevel)) return false; } break; case PGC_INT: { - const struct config_int *conf = (const struct config_int *) record; + const struct config_int *conf = &record->_int; const char *hintmsg; if (!parse_int(value, &newval->intval, - conf->gen.flags, &hintmsg)) + record->flags, &hintmsg)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value for parameter \"%s\": \"%s\"", - conf->gen.name, value), + record->name, value), hintmsg ? errhint("%s", _(hintmsg)) : 0)); return false; } if (newval->intval < conf->min || newval->intval > conf->max) { - const char *unit = get_config_unit_name(conf->gen.flags); + const char *unit = get_config_unit_name(record->flags); const char *unitspace; if (unit) @@ -3116,36 +3046,36 @@ parse_and_validate_value(const struct config_generic *record, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("%d%s%s is outside the valid range for parameter \"%s\" (%d%s%s .. %d%s%s)", newval->intval, unitspace, unit, - conf->gen.name, + record->name, conf->min, unitspace, unit, conf->max, unitspace, unit))); return false; } - if (!call_int_check_hook(conf, &newval->intval, newextra, + if (!call_int_check_hook(record, &newval->intval, newextra, source, elevel)) return false; } break; case PGC_REAL: { - const struct config_real *conf = (const struct config_real *) record; + const struct config_real *conf = &record->_real; const char *hintmsg; if (!parse_real(value, &newval->realval, - conf->gen.flags, &hintmsg)) + record->flags, &hintmsg)) { ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value for parameter \"%s\": \"%s\"", - conf->gen.name, value), + record->name, value), hintmsg ? errhint("%s", _(hintmsg)) : 0)); return false; } if (newval->realval < conf->min || newval->realval > conf->max) { - const char *unit = get_config_unit_name(conf->gen.flags); + const char *unit = get_config_unit_name(record->flags); const char *unitspace; if (unit) @@ -3157,21 +3087,19 @@ parse_and_validate_value(const struct config_generic *record, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("%g%s%s is outside the valid range for parameter \"%s\" (%g%s%s .. %g%s%s)", newval->realval, unitspace, unit, - conf->gen.name, + record->name, conf->min, unitspace, unit, conf->max, unitspace, unit))); return false; } - if (!call_real_check_hook(conf, &newval->realval, newextra, + if (!call_real_check_hook(record, &newval->realval, newextra, source, elevel)) return false; } break; case PGC_STRING: { - const struct config_string *conf = (const struct config_string *) record; - /* * The value passed by the caller could be transient, so we * always strdup it. @@ -3184,12 +3112,12 @@ parse_and_validate_value(const struct config_generic *record, * The only built-in "parsing" check we have is to apply * truncation if GUC_IS_NAME. */ - if (conf->gen.flags & GUC_IS_NAME) + if (record->flags & GUC_IS_NAME) truncate_identifier(newval->stringval, strlen(newval->stringval), true); - if (!call_string_check_hook(conf, &newval->stringval, newextra, + if (!call_string_check_hook(record, &newval->stringval, newextra, source, elevel)) { guc_free(newval->stringval); @@ -3200,7 +3128,7 @@ parse_and_validate_value(const struct config_generic *record, break; case PGC_ENUM: { - const struct config_enum *conf = (const struct config_enum *) record; + const struct config_enum *conf = &record->_enum; if (!config_enum_lookup_by_name(conf, value, &newval->enumval)) { @@ -3213,7 +3141,7 @@ parse_and_validate_value(const struct config_generic *record, ereport(elevel, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value for parameter \"%s\": \"%s\"", - conf->gen.name, value), + record->name, value), hintmsg ? errhint("%s", _(hintmsg)) : 0)); if (hintmsg) @@ -3221,7 +3149,7 @@ parse_and_validate_value(const struct config_generic *record, return false; } - if (!call_enum_check_hook(conf, &newval->enumval, newextra, + if (!call_enum_check_hook(record, &newval->enumval, newextra, source, elevel)) return false; } @@ -3639,7 +3567,7 @@ set_config_with_handle(const char *name, config_handle *handle, { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) record; + struct config_bool *conf = &record->_bool; #define newval (newval_union.boolval) @@ -3653,23 +3581,23 @@ set_config_with_handle(const char *name, config_handle *handle, else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_bool_check_hook(conf, &newval, &newextra, + if (!call_bool_check_hook(record, &newval, &newextra, source, elevel)) return 0; } else { newval = conf->reset_val; - newextra = conf->gen.reset_extra; - source = conf->gen.reset_source; - context = conf->gen.reset_scontext; - srole = conf->gen.reset_srole; + newextra = record->reset_extra; + source = record->reset_source; + context = record->reset_scontext; + srole = record->reset_srole; } if (prohibitValueChange) { /* Release newextra, unless it's reset_extra */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); if (*conf->variable != newval) @@ -3678,7 +3606,7 @@ set_config_with_handle(const char *name, config_handle *handle, ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed without restarting the server", - conf->gen.name))); + record->name))); return 0; } record->status &= ~GUC_PENDING_RESTART; @@ -3689,34 +3617,34 @@ set_config_with_handle(const char *name, config_handle *handle, { /* Save old value to support transaction abort */ if (!makeDefault) - push_old_value(&conf->gen, action); + push_old_value(record, action); if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(record, &record->extra, newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + set_guc_source(record, source); + record->scontext = context; + record->srole = srole; } if (makeDefault) { - if (conf->gen.reset_source <= source) + if (record->reset_source <= source) { conf->reset_val = newval; - set_extra_field(&conf->gen, &conf->gen.reset_extra, + set_extra_field(record, &record->reset_extra, newextra); - conf->gen.reset_source = source; - conf->gen.reset_scontext = context; - conf->gen.reset_srole = srole; + record->reset_source = source; + record->reset_scontext = context; + record->reset_srole = srole; } - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = record->stack; stack; stack = stack->prev) { if (stack->source <= source) { stack->prior.val.boolval = newval; - set_extra_field(&conf->gen, &stack->prior.extra, + set_extra_field(record, &stack->prior.extra, newextra); stack->source = source; stack->scontext = context; @@ -3726,7 +3654,7 @@ set_config_with_handle(const char *name, config_handle *handle, } /* Perhaps we didn't install newextra anywhere */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); break; @@ -3735,7 +3663,7 @@ set_config_with_handle(const char *name, config_handle *handle, case PGC_INT: { - struct config_int *conf = (struct config_int *) record; + struct config_int *conf = &record->_int; #define newval (newval_union.intval) @@ -3749,23 +3677,23 @@ set_config_with_handle(const char *name, config_handle *handle, else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_int_check_hook(conf, &newval, &newextra, + if (!call_int_check_hook(record, &newval, &newextra, source, elevel)) return 0; } else { newval = conf->reset_val; - newextra = conf->gen.reset_extra; - source = conf->gen.reset_source; - context = conf->gen.reset_scontext; - srole = conf->gen.reset_srole; + newextra = record->reset_extra; + source = record->reset_source; + context = record->reset_scontext; + srole = record->reset_srole; } if (prohibitValueChange) { /* Release newextra, unless it's reset_extra */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); if (*conf->variable != newval) @@ -3774,7 +3702,7 @@ set_config_with_handle(const char *name, config_handle *handle, ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed without restarting the server", - conf->gen.name))); + record->name))); return 0; } record->status &= ~GUC_PENDING_RESTART; @@ -3785,34 +3713,34 @@ set_config_with_handle(const char *name, config_handle *handle, { /* Save old value to support transaction abort */ if (!makeDefault) - push_old_value(&conf->gen, action); + push_old_value(record, action); if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(record, &record->extra, newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + set_guc_source(record, source); + record->scontext = context; + record->srole = srole; } if (makeDefault) { - if (conf->gen.reset_source <= source) + if (record->reset_source <= source) { conf->reset_val = newval; - set_extra_field(&conf->gen, &conf->gen.reset_extra, + set_extra_field(record, &record->reset_extra, newextra); - conf->gen.reset_source = source; - conf->gen.reset_scontext = context; - conf->gen.reset_srole = srole; + record->reset_source = source; + record->reset_scontext = context; + record->reset_srole = srole; } - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = record->stack; stack; stack = stack->prev) { if (stack->source <= source) { stack->prior.val.intval = newval; - set_extra_field(&conf->gen, &stack->prior.extra, + set_extra_field(record, &stack->prior.extra, newextra); stack->source = source; stack->scontext = context; @@ -3822,7 +3750,7 @@ set_config_with_handle(const char *name, config_handle *handle, } /* Perhaps we didn't install newextra anywhere */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); break; @@ -3831,7 +3759,7 @@ set_config_with_handle(const char *name, config_handle *handle, case PGC_REAL: { - struct config_real *conf = (struct config_real *) record; + struct config_real *conf = &record->_real; #define newval (newval_union.realval) @@ -3845,23 +3773,23 @@ set_config_with_handle(const char *name, config_handle *handle, else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_real_check_hook(conf, &newval, &newextra, + if (!call_real_check_hook(record, &newval, &newextra, source, elevel)) return 0; } else { newval = conf->reset_val; - newextra = conf->gen.reset_extra; - source = conf->gen.reset_source; - context = conf->gen.reset_scontext; - srole = conf->gen.reset_srole; + newextra = record->reset_extra; + source = record->reset_source; + context = record->reset_scontext; + srole = record->reset_srole; } if (prohibitValueChange) { /* Release newextra, unless it's reset_extra */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); if (*conf->variable != newval) @@ -3870,7 +3798,7 @@ set_config_with_handle(const char *name, config_handle *handle, ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed without restarting the server", - conf->gen.name))); + record->name))); return 0; } record->status &= ~GUC_PENDING_RESTART; @@ -3881,34 +3809,34 @@ set_config_with_handle(const char *name, config_handle *handle, { /* Save old value to support transaction abort */ if (!makeDefault) - push_old_value(&conf->gen, action); + push_old_value(record, action); if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(record, &record->extra, newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + set_guc_source(record, source); + record->scontext = context; + record->srole = srole; } if (makeDefault) { - if (conf->gen.reset_source <= source) + if (record->reset_source <= source) { conf->reset_val = newval; - set_extra_field(&conf->gen, &conf->gen.reset_extra, + set_extra_field(record, &record->reset_extra, newextra); - conf->gen.reset_source = source; - conf->gen.reset_scontext = context; - conf->gen.reset_srole = srole; + record->reset_source = source; + record->reset_scontext = context; + record->reset_srole = srole; } - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = record->stack; stack; stack = stack->prev) { if (stack->source <= source) { stack->prior.val.realval = newval; - set_extra_field(&conf->gen, &stack->prior.extra, + set_extra_field(record, &stack->prior.extra, newextra); stack->source = source; stack->scontext = context; @@ -3918,7 +3846,7 @@ set_config_with_handle(const char *name, config_handle *handle, } /* Perhaps we didn't install newextra anywhere */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); break; @@ -3927,7 +3855,7 @@ set_config_with_handle(const char *name, config_handle *handle, case PGC_STRING: { - struct config_string *conf = (struct config_string *) record; + struct config_string *conf = &record->_string; GucContext orig_context = context; GucSource orig_source = source; Oid orig_srole = srole; @@ -3953,7 +3881,7 @@ set_config_with_handle(const char *name, config_handle *handle, else newval = NULL; - if (!call_string_check_hook(conf, &newval, &newextra, + if (!call_string_check_hook(record, &newval, &newextra, source, elevel)) { guc_free(newval); @@ -3967,10 +3895,10 @@ set_config_with_handle(const char *name, config_handle *handle, * guc.c's control */ newval = conf->reset_val; - newextra = conf->gen.reset_extra; - source = conf->gen.reset_source; - context = conf->gen.reset_scontext; - srole = conf->gen.reset_srole; + newextra = record->reset_extra; + source = record->reset_source; + context = record->reset_scontext; + srole = record->reset_srole; } if (prohibitValueChange) @@ -3983,10 +3911,10 @@ set_config_with_handle(const char *name, config_handle *handle, strcmp(*conf->variable, newval) != 0); /* Release newval, unless it's reset_val */ - if (newval && !string_field_used(conf, newval)) + if (newval && !string_field_used(record, newval)) guc_free(newval); /* Release newextra, unless it's reset_extra */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); if (newval_different) @@ -3995,7 +3923,7 @@ set_config_with_handle(const char *name, config_handle *handle, ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed without restarting the server", - conf->gen.name))); + record->name))); return 0; } record->status &= ~GUC_PENDING_RESTART; @@ -4006,16 +3934,16 @@ set_config_with_handle(const char *name, config_handle *handle, { /* Save old value to support transaction abort */ if (!makeDefault) - push_old_value(&conf->gen, action); + push_old_value(record, action); if (conf->assign_hook) conf->assign_hook(newval, newextra); - set_string_field(conf, conf->variable, newval); - set_extra_field(&conf->gen, &conf->gen.extra, + set_string_field(record, conf->variable, newval); + set_extra_field(record, &record->extra, newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + set_guc_source(record, source); + record->scontext = context; + record->srole = srole; /* * Ugly hack: during SET session_authorization, forcibly @@ -4042,7 +3970,7 @@ set_config_with_handle(const char *name, config_handle *handle, * that. */ if (!is_reload && - strcmp(conf->gen.name, "session_authorization") == 0) + strcmp(record->name, "session_authorization") == 0) (void) set_config_with_handle("role", NULL, value ? "none" : NULL, orig_context, @@ -4058,22 +3986,22 @@ set_config_with_handle(const char *name, config_handle *handle, if (makeDefault) { - if (conf->gen.reset_source <= source) + if (record->reset_source <= source) { - set_string_field(conf, &conf->reset_val, newval); - set_extra_field(&conf->gen, &conf->gen.reset_extra, + set_string_field(record, &conf->reset_val, newval); + set_extra_field(record, &record->reset_extra, newextra); - conf->gen.reset_source = source; - conf->gen.reset_scontext = context; - conf->gen.reset_srole = srole; + record->reset_source = source; + record->reset_scontext = context; + record->reset_srole = srole; } - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = record->stack; stack; stack = stack->prev) { if (stack->source <= source) { - set_string_field(conf, &stack->prior.val.stringval, + set_string_field(record, &stack->prior.val.stringval, newval); - set_extra_field(&conf->gen, &stack->prior.extra, + set_extra_field(record, &stack->prior.extra, newextra); stack->source = source; stack->scontext = context; @@ -4083,10 +4011,10 @@ set_config_with_handle(const char *name, config_handle *handle, } /* Perhaps we didn't install newval anywhere */ - if (newval && !string_field_used(conf, newval)) + if (newval && !string_field_used(record, newval)) guc_free(newval); /* Perhaps we didn't install newextra anywhere */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); break; @@ -4095,7 +4023,7 @@ set_config_with_handle(const char *name, config_handle *handle, case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) record; + struct config_enum *conf = &record->_enum; #define newval (newval_union.enumval) @@ -4109,23 +4037,23 @@ set_config_with_handle(const char *name, config_handle *handle, else if (source == PGC_S_DEFAULT) { newval = conf->boot_val; - if (!call_enum_check_hook(conf, &newval, &newextra, + if (!call_enum_check_hook(record, &newval, &newextra, source, elevel)) return 0; } else { newval = conf->reset_val; - newextra = conf->gen.reset_extra; - source = conf->gen.reset_source; - context = conf->gen.reset_scontext; - srole = conf->gen.reset_srole; + newextra = record->reset_extra; + source = record->reset_source; + context = record->reset_scontext; + srole = record->reset_srole; } if (prohibitValueChange) { /* Release newextra, unless it's reset_extra */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); if (*conf->variable != newval) @@ -4134,7 +4062,7 @@ set_config_with_handle(const char *name, config_handle *handle, ereport(elevel, (errcode(ERRCODE_CANT_CHANGE_RUNTIME_PARAM), errmsg("parameter \"%s\" cannot be changed without restarting the server", - conf->gen.name))); + record->name))); return 0; } record->status &= ~GUC_PENDING_RESTART; @@ -4145,34 +4073,34 @@ set_config_with_handle(const char *name, config_handle *handle, { /* Save old value to support transaction abort */ if (!makeDefault) - push_old_value(&conf->gen, action); + push_old_value(record, action); if (conf->assign_hook) conf->assign_hook(newval, newextra); *conf->variable = newval; - set_extra_field(&conf->gen, &conf->gen.extra, + set_extra_field(record, &record->extra, newextra); - set_guc_source(&conf->gen, source); - conf->gen.scontext = context; - conf->gen.srole = srole; + set_guc_source(record, source); + record->scontext = context; + record->srole = srole; } if (makeDefault) { - if (conf->gen.reset_source <= source) + if (record->reset_source <= source) { conf->reset_val = newval; - set_extra_field(&conf->gen, &conf->gen.reset_extra, + set_extra_field(record, &record->reset_extra, newextra); - conf->gen.reset_source = source; - conf->gen.reset_scontext = context; - conf->gen.reset_srole = srole; + record->reset_source = source; + record->reset_scontext = context; + record->reset_srole = srole; } - for (GucStack *stack = conf->gen.stack; stack; stack = stack->prev) + for (GucStack *stack = record->stack; stack; stack = stack->prev) { if (stack->source <= source) { stack->prior.val.enumval = newval; - set_extra_field(&conf->gen, &stack->prior.extra, + set_extra_field(record, &stack->prior.extra, newextra); stack->source = source; stack->scontext = context; @@ -4182,7 +4110,7 @@ set_config_with_handle(const char *name, config_handle *handle, } /* Perhaps we didn't install newextra anywhere */ - if (newextra && !extra_field_used(&conf->gen, newextra)) + if (newextra && !extra_field_used(record, newextra)) guc_free(newextra); break; @@ -4296,25 +4224,25 @@ GetConfigOption(const char *name, bool missing_ok, bool restrict_privileged) switch (record->vartype) { case PGC_BOOL: - return *((struct config_bool *) record)->variable ? "on" : "off"; + return *record->_bool.variable ? "on" : "off"; case PGC_INT: snprintf(buffer, sizeof(buffer), "%d", - *((struct config_int *) record)->variable); + *record->_int.variable); return buffer; case PGC_REAL: snprintf(buffer, sizeof(buffer), "%g", - *((struct config_real *) record)->variable); + *record->_real.variable); return buffer; case PGC_STRING: - return *((struct config_string *) record)->variable ? - *((struct config_string *) record)->variable : ""; + return *record->_string.variable ? + *record->_string.variable : ""; case PGC_ENUM: - return config_enum_lookup_by_value((struct config_enum *) record, - *((struct config_enum *) record)->variable); + return config_enum_lookup_by_value(record, + *record->_enum.variable); } return NULL; } @@ -4344,25 +4272,25 @@ GetConfigOptionResetString(const char *name) switch (record->vartype) { case PGC_BOOL: - return ((struct config_bool *) record)->reset_val ? "on" : "off"; + return record->_bool.reset_val ? "on" : "off"; case PGC_INT: snprintf(buffer, sizeof(buffer), "%d", - ((struct config_int *) record)->reset_val); + record->_int.reset_val); return buffer; case PGC_REAL: snprintf(buffer, sizeof(buffer), "%g", - ((struct config_real *) record)->reset_val); + record->_real.reset_val); return buffer; case PGC_STRING: - return ((struct config_string *) record)->reset_val ? - ((struct config_string *) record)->reset_val : ""; + return record->_string.reset_val ? + record->_string.reset_val : ""; case PGC_ENUM: - return config_enum_lookup_by_value((struct config_enum *) record, - ((struct config_enum *) record)->reset_val); + return config_enum_lookup_by_value(record, + record->_enum.reset_val); } return NULL; } @@ -4802,8 +4730,7 @@ init_custom_variable(const char *name, const char *long_desc, GucContext context, int flags, - enum config_type type, - size_t sz) + enum config_type type) { struct config_generic *gen; @@ -4839,8 +4766,8 @@ init_custom_variable(const char *name, context = PGC_SUSET; /* As above, an OOM here is FATAL */ - gen = (struct config_generic *) guc_malloc(FATAL, sz); - memset(gen, 0, sz); + gen = (struct config_generic *) guc_malloc(FATAL, sizeof(struct config_generic)); + memset(gen, 0, sizeof(struct config_generic)); gen->name = guc_strdup(FATAL, name); gen->context = context; @@ -4862,7 +4789,7 @@ define_custom_variable(struct config_generic *variable) { const char *name = variable->name; GUCHashEntry *hentry; - struct config_string *pHolder; + struct config_generic *pHolder; /* Check mapping between initial and default value */ Assert(check_GUC_init(variable)); @@ -4894,7 +4821,7 @@ define_custom_variable(struct config_generic *variable) errmsg("attempt to redefine parameter \"%s\"", name))); Assert(hentry->gucvar->vartype == PGC_STRING); - pHolder = (struct config_string *) hentry->gucvar; + pHolder = hentry->gucvar; /* * First, set the variable to its default value. We must do this even @@ -4913,7 +4840,7 @@ define_custom_variable(struct config_generic *variable) /* * Remove the placeholder from any lists it's in, too. */ - RemoveGUCFromLists(&pHolder->gen); + RemoveGUCFromLists(pHolder); /* * Assign the string value(s) stored in the placeholder to the real @@ -4927,25 +4854,25 @@ define_custom_variable(struct config_generic *variable) */ /* First, apply the reset value if any */ - if (pHolder->reset_val) - (void) set_config_option_ext(name, pHolder->reset_val, - pHolder->gen.reset_scontext, - pHolder->gen.reset_source, - pHolder->gen.reset_srole, + if (pHolder->_string.reset_val) + (void) set_config_option_ext(name, pHolder->_string.reset_val, + pHolder->reset_scontext, + pHolder->reset_source, + pHolder->reset_srole, GUC_ACTION_SET, true, WARNING, false); /* That should not have resulted in stacking anything */ Assert(variable->stack == NULL); /* Now, apply current and stacked values, in the order they were stacked */ - reapply_stacked_values(variable, pHolder, pHolder->gen.stack, - *(pHolder->variable), - pHolder->gen.scontext, pHolder->gen.source, - pHolder->gen.srole); + reapply_stacked_values(variable, pHolder, pHolder->stack, + *(pHolder->_string.variable), + pHolder->scontext, pHolder->source, + pHolder->srole); /* Also copy over any saved source-location information */ - if (pHolder->gen.sourcefile) - set_config_sourcefile(name, pHolder->gen.sourcefile, - pHolder->gen.sourceline); + if (pHolder->sourcefile) + set_config_sourcefile(name, pHolder->sourcefile, + pHolder->sourceline); /* Now we can free the no-longer-referenced placeholder variable */ free_placeholder(pHolder); @@ -4960,7 +4887,7 @@ define_custom_variable(struct config_generic *variable) */ static void reapply_stacked_values(struct config_generic *variable, - struct config_string *pHolder, + struct config_generic *pHolder, GucStack *stack, const char *curvalue, GucContext curscontext, GucSource cursource, @@ -5030,10 +4957,10 @@ reapply_stacked_values(struct config_generic *variable, * this is to be just a transactional assignment. (We leak the stack * entry.) */ - if (curvalue != pHolder->reset_val || - curscontext != pHolder->gen.reset_scontext || - cursource != pHolder->gen.reset_source || - cursrole != pHolder->gen.reset_srole) + if (curvalue != pHolder->_string.reset_val || + curscontext != pHolder->reset_scontext || + cursource != pHolder->reset_source || + cursrole != pHolder->reset_srole) { (void) set_config_option_ext(name, curvalue, curscontext, cursource, cursrole, @@ -5055,14 +4982,14 @@ reapply_stacked_values(struct config_generic *variable, * doesn't seem worth spending much code on. */ static void -free_placeholder(struct config_string *pHolder) +free_placeholder(struct config_generic *pHolder) { /* Placeholders are always STRING type, so free their values */ - Assert(pHolder->gen.vartype == PGC_STRING); - set_string_field(pHolder, pHolder->variable, NULL); - set_string_field(pHolder, &pHolder->reset_val, NULL); + Assert(pHolder->vartype == PGC_STRING); + set_string_field(pHolder, pHolder->_string.variable, NULL); + set_string_field(pHolder, &pHolder->_string.reset_val, NULL); - guc_free(unconstify(char *, pHolder->gen.name)); + guc_free(unconstify(char *, pHolder->name)); guc_free(pHolder); } @@ -5081,18 +5008,16 @@ DefineCustomBoolVariable(const char *name, GucBoolAssignHook assign_hook, GucShowHook show_hook) { - struct config_bool *var; - - var = (struct config_bool *) - init_custom_variable(name, short_desc, long_desc, context, flags, - PGC_BOOL, sizeof(struct config_bool)); - var->variable = valueAddr; - var->boot_val = bootValue; - var->reset_val = bootValue; - var->check_hook = check_hook; - var->assign_hook = assign_hook; - var->show_hook = show_hook; - define_custom_variable(&var->gen); + struct config_generic *var; + + var = init_custom_variable(name, short_desc, long_desc, context, flags, PGC_BOOL); + var->_bool.variable = valueAddr; + var->_bool.boot_val = bootValue; + var->_bool.reset_val = bootValue; + var->_bool.check_hook = check_hook; + var->_bool.assign_hook = assign_hook; + var->_bool.show_hook = show_hook; + define_custom_variable(var); } void @@ -5109,20 +5034,18 @@ DefineCustomIntVariable(const char *name, GucIntAssignHook assign_hook, GucShowHook show_hook) { - struct config_int *var; - - var = (struct config_int *) - init_custom_variable(name, short_desc, long_desc, context, flags, - PGC_INT, sizeof(struct config_int)); - var->variable = valueAddr; - var->boot_val = bootValue; - var->reset_val = bootValue; - var->min = minValue; - var->max = maxValue; - var->check_hook = check_hook; - var->assign_hook = assign_hook; - var->show_hook = show_hook; - define_custom_variable(&var->gen); + struct config_generic *var; + + var = init_custom_variable(name, short_desc, long_desc, context, flags, PGC_INT); + var->_int.variable = valueAddr; + var->_int.boot_val = bootValue; + var->_int.reset_val = bootValue; + var->_int.min = minValue; + var->_int.max = maxValue; + var->_int.check_hook = check_hook; + var->_int.assign_hook = assign_hook; + var->_int.show_hook = show_hook; + define_custom_variable(var); } void @@ -5139,20 +5062,18 @@ DefineCustomRealVariable(const char *name, GucRealAssignHook assign_hook, GucShowHook show_hook) { - struct config_real *var; - - var = (struct config_real *) - init_custom_variable(name, short_desc, long_desc, context, flags, - PGC_REAL, sizeof(struct config_real)); - var->variable = valueAddr; - var->boot_val = bootValue; - var->reset_val = bootValue; - var->min = minValue; - var->max = maxValue; - var->check_hook = check_hook; - var->assign_hook = assign_hook; - var->show_hook = show_hook; - define_custom_variable(&var->gen); + struct config_generic *var; + + var = init_custom_variable(name, short_desc, long_desc, context, flags, PGC_REAL); + var->_real.variable = valueAddr; + var->_real.boot_val = bootValue; + var->_real.reset_val = bootValue; + var->_real.min = minValue; + var->_real.max = maxValue; + var->_real.check_hook = check_hook; + var->_real.assign_hook = assign_hook; + var->_real.show_hook = show_hook; + define_custom_variable(var); } void @@ -5167,17 +5088,15 @@ DefineCustomStringVariable(const char *name, GucStringAssignHook assign_hook, GucShowHook show_hook) { - struct config_string *var; - - var = (struct config_string *) - init_custom_variable(name, short_desc, long_desc, context, flags, - PGC_STRING, sizeof(struct config_string)); - var->variable = valueAddr; - var->boot_val = bootValue; - var->check_hook = check_hook; - var->assign_hook = assign_hook; - var->show_hook = show_hook; - define_custom_variable(&var->gen); + struct config_generic *var; + + var = init_custom_variable(name, short_desc, long_desc, context, flags, PGC_STRING); + var->_string.variable = valueAddr; + var->_string.boot_val = bootValue; + var->_string.check_hook = check_hook; + var->_string.assign_hook = assign_hook; + var->_string.show_hook = show_hook; + define_custom_variable(var); } void @@ -5193,19 +5112,17 @@ DefineCustomEnumVariable(const char *name, GucEnumAssignHook assign_hook, GucShowHook show_hook) { - struct config_enum *var; - - var = (struct config_enum *) - init_custom_variable(name, short_desc, long_desc, context, flags, - PGC_ENUM, sizeof(struct config_enum)); - var->variable = valueAddr; - var->boot_val = bootValue; - var->reset_val = bootValue; - var->options = options; - var->check_hook = check_hook; - var->assign_hook = assign_hook; - var->show_hook = show_hook; - define_custom_variable(&var->gen); + struct config_generic *var; + + var = init_custom_variable(name, short_desc, long_desc, context, flags, PGC_ENUM); + var->_enum.variable = valueAddr; + var->_enum.boot_val = bootValue; + var->_enum.reset_val = bootValue; + var->_enum.options = options; + var->_enum.check_hook = check_hook; + var->_enum.assign_hook = assign_hook; + var->_enum.show_hook = show_hook; + define_custom_variable(var); } /* @@ -5251,7 +5168,7 @@ MarkGUCPrefixReserved(const char *className) /* Remove it from any lists it's in, too */ RemoveGUCFromLists(var); /* And free it */ - free_placeholder((struct config_string *) var); + free_placeholder(var); } } @@ -5304,7 +5221,7 @@ get_explain_guc_options(int *num) { case PGC_BOOL: { - struct config_bool *lconf = (struct config_bool *) conf; + struct config_bool *lconf = &conf->_bool; modified = (lconf->boot_val != *(lconf->variable)); } @@ -5312,7 +5229,7 @@ get_explain_guc_options(int *num) case PGC_INT: { - struct config_int *lconf = (struct config_int *) conf; + struct config_int *lconf = &conf->_int; modified = (lconf->boot_val != *(lconf->variable)); } @@ -5320,7 +5237,7 @@ get_explain_guc_options(int *num) case PGC_REAL: { - struct config_real *lconf = (struct config_real *) conf; + struct config_real *lconf = &conf->_real; modified = (lconf->boot_val != *(lconf->variable)); } @@ -5328,7 +5245,7 @@ get_explain_guc_options(int *num) case PGC_STRING: { - struct config_string *lconf = (struct config_string *) conf; + struct config_string *lconf = &conf->_string; if (lconf->boot_val == NULL && *lconf->variable == NULL) @@ -5343,7 +5260,7 @@ get_explain_guc_options(int *num) case PGC_ENUM: { - struct config_enum *lconf = (struct config_enum *) conf; + struct config_enum *lconf = &conf->_enum; modified = (lconf->boot_val != *(lconf->variable)); } @@ -5412,7 +5329,7 @@ ShowGUCOption(const struct config_generic *record, bool use_units) { case PGC_BOOL: { - const struct config_bool *conf = (const struct config_bool *) record; + const struct config_bool *conf = &record->_bool; if (conf->show_hook) val = conf->show_hook(); @@ -5423,7 +5340,7 @@ ShowGUCOption(const struct config_generic *record, bool use_units) case PGC_INT: { - const struct config_int *conf = (const struct config_int *) record; + const struct config_int *conf = &record->_int; if (conf->show_hook) val = conf->show_hook(); @@ -5452,7 +5369,7 @@ ShowGUCOption(const struct config_generic *record, bool use_units) case PGC_REAL: { - const struct config_real *conf = (const struct config_real *) record; + const struct config_real *conf = &record->_real; if (conf->show_hook) val = conf->show_hook(); @@ -5477,7 +5394,7 @@ ShowGUCOption(const struct config_generic *record, bool use_units) case PGC_STRING: { - const struct config_string *conf = (const struct config_string *) record; + const struct config_string *conf = &record->_string; if (conf->show_hook) val = conf->show_hook(); @@ -5490,12 +5407,12 @@ ShowGUCOption(const struct config_generic *record, bool use_units) case PGC_ENUM: { - const struct config_enum *conf = (const struct config_enum *) record; + const struct config_enum *conf = &record->_enum; if (conf->show_hook) val = conf->show_hook(); else - val = config_enum_lookup_by_value(conf, *conf->variable); + val = config_enum_lookup_by_value(record, *conf->variable); } break; @@ -5535,7 +5452,7 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) gconf; + struct config_bool *conf = &gconf->_bool; if (*conf->variable) fprintf(fp, "true"); @@ -5546,7 +5463,7 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; fprintf(fp, "%d", *conf->variable); } @@ -5554,7 +5471,7 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) case PGC_REAL: { - struct config_real *conf = (struct config_real *) gconf; + struct config_real *conf = &gconf->_real; fprintf(fp, "%.17g", *conf->variable); } @@ -5562,7 +5479,7 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; if (*conf->variable) fprintf(fp, "%s", *conf->variable); @@ -5571,10 +5488,10 @@ write_one_nondefault_variable(FILE *fp, struct config_generic *gconf) case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; fprintf(fp, "%s", - config_enum_lookup_by_value(conf, *conf->variable)); + config_enum_lookup_by_value(gconf, *conf->variable)); } break; } @@ -5809,7 +5726,7 @@ estimate_variable_size(struct config_generic *gconf) case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; /* * Instead of getting the exact display length, use max @@ -5838,7 +5755,7 @@ estimate_variable_size(struct config_generic *gconf) case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; /* * If the value is NULL, we transmit it as an empty string. @@ -5854,9 +5771,9 @@ estimate_variable_size(struct config_generic *gconf) case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; - valsize = strlen(config_enum_lookup_by_value(conf, *conf->variable)); + valsize = strlen(config_enum_lookup_by_value(gconf, *conf->variable)); } break; } @@ -5975,7 +5892,7 @@ serialize_variable(char **destptr, Size *maxbytes, { case PGC_BOOL: { - struct config_bool *conf = (struct config_bool *) gconf; + struct config_bool *conf = &gconf->_bool; do_serialize(destptr, maxbytes, (*conf->variable ? "true" : "false")); @@ -5984,7 +5901,7 @@ serialize_variable(char **destptr, Size *maxbytes, case PGC_INT: { - struct config_int *conf = (struct config_int *) gconf; + struct config_int *conf = &gconf->_int; do_serialize(destptr, maxbytes, "%d", *conf->variable); } @@ -5992,7 +5909,7 @@ serialize_variable(char **destptr, Size *maxbytes, case PGC_REAL: { - struct config_real *conf = (struct config_real *) gconf; + struct config_real *conf = &gconf->_real; do_serialize(destptr, maxbytes, "%.*e", REALTYPE_PRECISION, *conf->variable); @@ -6001,7 +5918,7 @@ serialize_variable(char **destptr, Size *maxbytes, case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; /* NULL becomes empty string, see estimate_variable_size() */ do_serialize(destptr, maxbytes, "%s", @@ -6011,10 +5928,10 @@ serialize_variable(char **destptr, Size *maxbytes, case PGC_ENUM: { - struct config_enum *conf = (struct config_enum *) gconf; + struct config_enum *conf = &gconf->_enum; do_serialize(destptr, maxbytes, "%s", - config_enum_lookup_by_value(conf, *conf->variable)); + config_enum_lookup_by_value(gconf, *conf->variable)); } break; } @@ -6199,7 +6116,7 @@ RestoreGUCState(void *gucstate) break; case PGC_STRING: { - struct config_string *conf = (struct config_string *) gconf; + struct config_string *conf = &gconf->_string; guc_free(*conf->variable); if (conf->reset_val && conf->reset_val != *conf->variable) @@ -6710,11 +6627,11 @@ GUC_check_errcode(int sqlerrcode) */ static bool -call_bool_check_hook(const struct config_bool *conf, bool *newval, void **extra, +call_bool_check_hook(const struct config_generic *conf, bool *newval, void **extra, GucSource source, int elevel) { /* Quick success if no hook */ - if (!conf->check_hook) + if (!conf->_bool.check_hook) return true; /* Reset variables that might be set by hook */ @@ -6723,14 +6640,14 @@ call_bool_check_hook(const struct config_bool *conf, bool *newval, void **extra, GUC_check_errdetail_string = NULL; GUC_check_errhint_string = NULL; - if (!conf->check_hook(newval, extra, source)) + if (!conf->_bool.check_hook(newval, extra, source)) { ereport(elevel, (errcode(GUC_check_errcode_value), GUC_check_errmsg_string ? errmsg_internal("%s", GUC_check_errmsg_string) : errmsg("invalid value for parameter \"%s\": %d", - conf->gen.name, (int) *newval), + conf->name, (int) *newval), GUC_check_errdetail_string ? errdetail_internal("%s", GUC_check_errdetail_string) : 0, GUC_check_errhint_string ? @@ -6744,11 +6661,11 @@ call_bool_check_hook(const struct config_bool *conf, bool *newval, void **extra, } static bool -call_int_check_hook(const struct config_int *conf, int *newval, void **extra, +call_int_check_hook(const struct config_generic *conf, int *newval, void **extra, GucSource source, int elevel) { /* Quick success if no hook */ - if (!conf->check_hook) + if (!conf->_int.check_hook) return true; /* Reset variables that might be set by hook */ @@ -6757,14 +6674,14 @@ call_int_check_hook(const struct config_int *conf, int *newval, void **extra, GUC_check_errdetail_string = NULL; GUC_check_errhint_string = NULL; - if (!conf->check_hook(newval, extra, source)) + if (!conf->_int.check_hook(newval, extra, source)) { ereport(elevel, (errcode(GUC_check_errcode_value), GUC_check_errmsg_string ? errmsg_internal("%s", GUC_check_errmsg_string) : errmsg("invalid value for parameter \"%s\": %d", - conf->gen.name, *newval), + conf->name, *newval), GUC_check_errdetail_string ? errdetail_internal("%s", GUC_check_errdetail_string) : 0, GUC_check_errhint_string ? @@ -6778,11 +6695,11 @@ call_int_check_hook(const struct config_int *conf, int *newval, void **extra, } static bool -call_real_check_hook(const struct config_real *conf, double *newval, void **extra, +call_real_check_hook(const struct config_generic *conf, double *newval, void **extra, GucSource source, int elevel) { /* Quick success if no hook */ - if (!conf->check_hook) + if (!conf->_real.check_hook) return true; /* Reset variables that might be set by hook */ @@ -6791,14 +6708,14 @@ call_real_check_hook(const struct config_real *conf, double *newval, void **extr GUC_check_errdetail_string = NULL; GUC_check_errhint_string = NULL; - if (!conf->check_hook(newval, extra, source)) + if (!conf->_real.check_hook(newval, extra, source)) { ereport(elevel, (errcode(GUC_check_errcode_value), GUC_check_errmsg_string ? errmsg_internal("%s", GUC_check_errmsg_string) : errmsg("invalid value for parameter \"%s\": %g", - conf->gen.name, *newval), + conf->name, *newval), GUC_check_errdetail_string ? errdetail_internal("%s", GUC_check_errdetail_string) : 0, GUC_check_errhint_string ? @@ -6812,13 +6729,13 @@ call_real_check_hook(const struct config_real *conf, double *newval, void **extr } static bool -call_string_check_hook(const struct config_string *conf, char **newval, void **extra, +call_string_check_hook(const struct config_generic *conf, char **newval, void **extra, GucSource source, int elevel) { volatile bool result = true; /* Quick success if no hook */ - if (!conf->check_hook) + if (!conf->_string.check_hook) return true; /* @@ -6834,14 +6751,14 @@ call_string_check_hook(const struct config_string *conf, char **newval, void **e GUC_check_errdetail_string = NULL; GUC_check_errhint_string = NULL; - if (!conf->check_hook(newval, extra, source)) + if (!conf->_string.check_hook(newval, extra, source)) { ereport(elevel, (errcode(GUC_check_errcode_value), GUC_check_errmsg_string ? errmsg_internal("%s", GUC_check_errmsg_string) : errmsg("invalid value for parameter \"%s\": \"%s\"", - conf->gen.name, *newval ? *newval : ""), + conf->name, *newval ? *newval : ""), GUC_check_errdetail_string ? errdetail_internal("%s", GUC_check_errdetail_string) : 0, GUC_check_errhint_string ? @@ -6862,11 +6779,11 @@ call_string_check_hook(const struct config_string *conf, char **newval, void **e } static bool -call_enum_check_hook(const struct config_enum *conf, int *newval, void **extra, +call_enum_check_hook(const struct config_generic *conf, int *newval, void **extra, GucSource source, int elevel) { /* Quick success if no hook */ - if (!conf->check_hook) + if (!conf->_enum.check_hook) return true; /* Reset variables that might be set by hook */ @@ -6875,14 +6792,14 @@ call_enum_check_hook(const struct config_enum *conf, int *newval, void **extra, GUC_check_errdetail_string = NULL; GUC_check_errhint_string = NULL; - if (!conf->check_hook(newval, extra, source)) + if (!conf->_enum.check_hook(newval, extra, source)) { ereport(elevel, (errcode(GUC_check_errcode_value), GUC_check_errmsg_string ? errmsg_internal("%s", GUC_check_errmsg_string) : errmsg("invalid value for parameter \"%s\": \"%s\"", - conf->gen.name, + conf->name, config_enum_lookup_by_value(conf, *newval)), GUC_check_errdetail_string ? errdetail_internal("%s", GUC_check_errdetail_string) : 0, diff --git a/src/backend/utils/misc/guc_funcs.c b/src/backend/utils/misc/guc_funcs.c index d7a822e1462..4f58fa3d4e0 100644 --- a/src/backend/utils/misc/guc_funcs.c +++ b/src/backend/utils/misc/guc_funcs.c @@ -629,7 +629,7 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) { case PGC_BOOL: { - const struct config_bool *lconf = (const struct config_bool *) conf; + const struct config_bool *lconf = &conf->_bool; /* min_val */ values[9] = NULL; @@ -650,7 +650,7 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) case PGC_INT: { - const struct config_int *lconf = (const struct config_int *) conf; + const struct config_int *lconf = &conf->_int; /* min_val */ snprintf(buffer, sizeof(buffer), "%d", lconf->min); @@ -675,7 +675,7 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) case PGC_REAL: { - const struct config_real *lconf = (const struct config_real *) conf; + const struct config_real *lconf = &conf->_real; /* min_val */ snprintf(buffer, sizeof(buffer), "%g", lconf->min); @@ -700,7 +700,7 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) case PGC_STRING: { - const struct config_string *lconf = (const struct config_string *) conf; + const struct config_string *lconf = &conf->_string; /* min_val */ values[9] = NULL; @@ -727,7 +727,7 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) case PGC_ENUM: { - const struct config_enum *lconf = (const struct config_enum *) conf; + const struct config_enum *lconf = &conf->_enum; /* min_val */ values[9] = NULL; @@ -745,11 +745,11 @@ GetConfigOptionValues(const struct config_generic *conf, const char **values) "{\"", "\"}", "\",\""); /* boot_val */ - values[12] = pstrdup(config_enum_lookup_by_value(lconf, + values[12] = pstrdup(config_enum_lookup_by_value(conf, lconf->boot_val)); /* reset_val */ - values[13] = pstrdup(config_enum_lookup_by_value(lconf, + values[13] = pstrdup(config_enum_lookup_by_value(conf, lconf->reset_val)); } break; diff --git a/src/backend/utils/misc/help_config.c b/src/backend/utils/misc/help_config.c index 86812ac881f..2810715693c 100644 --- a/src/backend/utils/misc/help_config.c +++ b/src/backend/utils/misc/help_config.c @@ -23,23 +23,8 @@ #include "utils/help_config.h" -/* - * This union allows us to mix the numerous different types of structs - * that we are organizing. - */ -typedef union -{ - struct config_generic generic; - struct config_bool _bool; - struct config_real real; - struct config_int integer; - struct config_string string; - struct config_enum _enum; -} mixedStruct; - - -static void printMixedStruct(mixedStruct *structToPrint); -static bool displayStruct(mixedStruct *structToDisplay); +static void printMixedStruct(const struct config_generic *structToPrint); +static bool displayStruct(const struct config_generic *structToDisplay); void @@ -55,7 +40,7 @@ GucInfoMain(void) for (int i = 0; i < numOpts; i++) { - mixedStruct *var = (mixedStruct *) guc_vars[i]; + const struct config_generic *var = guc_vars[i]; if (displayStruct(var)) printMixedStruct(var); @@ -70,11 +55,11 @@ GucInfoMain(void) * should be displayed to the user. */ static bool -displayStruct(mixedStruct *structToDisplay) +displayStruct(const struct config_generic *structToDisplay) { - return !(structToDisplay->generic.flags & (GUC_NO_SHOW_ALL | - GUC_NOT_IN_SAMPLE | - GUC_DISALLOW_IN_FILE)); + return !(structToDisplay->flags & (GUC_NO_SHOW_ALL | + GUC_NOT_IN_SAMPLE | + GUC_DISALLOW_IN_FILE)); } @@ -83,14 +68,14 @@ displayStruct(mixedStruct *structToDisplay) * a different format, depending on what the user wants to see. */ static void -printMixedStruct(mixedStruct *structToPrint) +printMixedStruct(const struct config_generic *structToPrint) { printf("%s\t%s\t%s\t", - structToPrint->generic.name, - GucContext_Names[structToPrint->generic.context], - _(config_group_names[structToPrint->generic.group])); + structToPrint->name, + GucContext_Names[structToPrint->context], + _(config_group_names[structToPrint->group])); - switch (structToPrint->generic.vartype) + switch (structToPrint->vartype) { case PGC_BOOL: @@ -101,26 +86,26 @@ printMixedStruct(mixedStruct *structToPrint) case PGC_INT: printf("INTEGER\t%d\t%d\t%d\t", - structToPrint->integer.reset_val, - structToPrint->integer.min, - structToPrint->integer.max); + structToPrint->_int.reset_val, + structToPrint->_int.min, + structToPrint->_int.max); break; case PGC_REAL: printf("REAL\t%g\t%g\t%g\t", - structToPrint->real.reset_val, - structToPrint->real.min, - structToPrint->real.max); + structToPrint->_real.reset_val, + structToPrint->_real.min, + structToPrint->_real.max); break; case PGC_STRING: printf("STRING\t%s\t\t\t", - structToPrint->string.boot_val ? structToPrint->string.boot_val : ""); + structToPrint->_string.boot_val ? structToPrint->_string.boot_val : ""); break; case PGC_ENUM: printf("ENUM\t%s\t\t\t", - config_enum_lookup_by_value(&structToPrint->_enum, + config_enum_lookup_by_value(structToPrint, structToPrint->_enum.boot_val)); break; @@ -130,6 +115,6 @@ printMixedStruct(mixedStruct *structToPrint) } printf("%s\t%s\n", - (structToPrint->generic.short_desc == NULL) ? "" : _(structToPrint->generic.short_desc), - (structToPrint->generic.long_desc == NULL) ? "" : _(structToPrint->generic.long_desc)); + (structToPrint->short_desc == NULL) ? "" : _(structToPrint->short_desc), + (structToPrint->long_desc == NULL) ? "" : _(structToPrint->long_desc)); } diff --git a/src/backend/utils/mmgr/aset.c b/src/backend/utils/mmgr/aset.c index d5ae1bdd3cd..bcd09c07533 100644 --- a/src/backend/utils/mmgr/aset.c +++ b/src/backend/utils/mmgr/aset.c @@ -1668,9 +1668,9 @@ AllocSetCheck(MemoryContext context) prevblock = block, block = block->next) { char *bpoz = ((char *) block) + ALLOC_BLOCKHDRSZ; - long blk_used = block->freeptr - bpoz; - long blk_data = 0; - long nchunks = 0; + Size blk_used = block->freeptr - bpoz; + Size blk_data = 0; + Size nchunks = 0; bool has_external_chunk = false; if (IsKeeperBlock(set, block)) diff --git a/src/backend/utils/sort/tuplesortvariants.c b/src/backend/utils/sort/tuplesortvariants.c index 890cdbe1204..41ac4afbf49 100644 --- a/src/backend/utils/sort/tuplesortvariants.c +++ b/src/backend/utils/sort/tuplesortvariants.c @@ -816,7 +816,7 @@ tuplesort_putheaptuple(Tuplesortstate *state, HeapTuple tup) */ void tuplesort_putindextuplevalues(Tuplesortstate *state, Relation rel, - ItemPointer self, const Datum *values, + const ItemPointerData *self, const Datum *values, const bool *isnull) { SortTuple stup; |
