public inbox for [email protected]
help / color / mirror / Atom feed[PATCH v3 5/5] Do COPY FROM encoding conversion/verification in larger chunks.
5+ messages / 4 participants
[nested] [flat]
* [PATCH v3 5/5] Do COPY FROM encoding conversion/verification in larger chunks.
@ 2021-01-28 16:42 Heikki Linnakangas <[email protected]>
0 siblings, 0 replies; 5+ messages in thread
From: Heikki Linnakangas @ 2021-01-28 16:42 UTC (permalink / raw)
NOTE: This changes behavior in one corner-case: if client and server
encodings are the same single-byte encoding (e.g. latin1), previously the
input would not be checked for zero bytes ('\0'). Any fields containing
zero bytes would be truncated at the zero. But if encoding conversion was
needed, the conversion routine would throw an error on the zero. After
this commit, the input is always checked for zeros.
---
src/backend/commands/copyfrom.c | 58 +--
src/backend/commands/copyfromparse.c | 473 ++++++++++++++++------
src/include/commands/copyfrom_internal.h | 53 +--
src/test/regress/expected/copycorners.out | 202 +++++++++
src/test/regress/sql/copycorners.sql | 90 ++++
5 files changed, 715 insertions(+), 161 deletions(-)
create mode 100644 src/test/regress/expected/copycorners.out
create mode 100644 src/test/regress/sql/copycorners.sql
diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c
index c39cc736ed2..3f787b885ae 100644
--- a/src/backend/commands/copyfrom.c
+++ b/src/backend/commands/copyfrom.c
@@ -3,6 +3,12 @@
* copyfrom.c
* COPY <table> FROM file/program/client
*
+ * This file contains routines needed to efficiently load tuples into a
+ * table. That includes looking up the correct partition, firing triggers,
+ * calling the table AM function to insert the data, and updating indexes.
+ * Reading data from the input file or client and parsing it into Datums
+ * is handled in copyfromparse.c.
+ *
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
@@ -23,6 +29,7 @@
#include "access/tableam.h"
#include "access/xact.h"
#include "access/xlog.h"
+#include "catalog/namespace.h"
#include "commands/copy.h"
#include "commands/copyfrom_internal.h"
#include "commands/progress.h"
@@ -149,15 +156,9 @@ CopyFromErrorCallback(void *arg)
/*
* Error is relevant to a particular line.
*
- * If line_buf still contains the correct line, and it's already
- * transcoded, print it. If it's still in a foreign encoding, it's
- * quite likely that the error is precisely a failure to do
- * encoding conversion (ie, bad data). We dare not try to convert
- * it, and at present there's no way to regurgitate it without
- * conversion. So we have to punt and just report the line number.
+ * If line_buf still contains the correct line, print it.
*/
- if (cstate->line_buf_valid &&
- (cstate->line_buf_converted || !cstate->need_transcoding))
+ if (cstate->line_buf_valid)
{
char *lineval;
@@ -1305,15 +1306,20 @@ BeginCopyFrom(ParseState *pstate,
cstate->file_encoding = cstate->opts.file_encoding;
/*
- * Set up encoding conversion info. Even if the file and server encodings
- * are the same, we must apply pg_any_to_server() to validate data in
- * multibyte encodings.
+ * Look up encoding conversion function.
*/
- cstate->need_transcoding =
- (cstate->file_encoding != GetDatabaseEncoding() ||
- pg_database_encoding_max_length() > 1);
- /* See Multibyte encoding comment above */
- cstate->encoding_embeds_ascii = PG_ENCODING_IS_CLIENT_ONLY(cstate->file_encoding);
+ if (cstate->file_encoding == GetDatabaseEncoding() ||
+ cstate->file_encoding == PG_SQL_ASCII ||
+ GetDatabaseEncoding() == PG_SQL_ASCII)
+ {
+ cstate->need_transcoding = false;
+ }
+ else
+ {
+ cstate->need_transcoding = true;
+ cstate->conversion_proc = FindDefaultConversionProc(cstate->file_encoding,
+ GetDatabaseEncoding());
+ }
cstate->copy_src = COPY_FILE; /* default */
@@ -1332,17 +1338,23 @@ BeginCopyFrom(ParseState *pstate,
cstate->cur_attval = NULL;
/*
- * Set up variables to avoid per-attribute overhead. attribute_buf and
- * raw_buf are used in both text and binary modes, but we use line_buf
- * only in text mode.
+ * Allocate buffers for the input pipeline.
+ *
+ * attribute_buf and input_buf are used in both text and binary modes, but
+ * we use line_buf only in text mode.
*/
initStringInfo(&cstate->attribute_buf);
- cstate->raw_buf = (char *) palloc(RAW_BUF_SIZE + 1);
- cstate->raw_buf_index = cstate->raw_buf_len = 0;
+
if (!cstate->opts.binary)
- {
initStringInfo(&cstate->line_buf);
- cstate->line_buf_converted = false;
+
+ cstate->input_buf = (char *) palloc(INPUT_BUF_SIZE + 1);
+ cstate->input_buf_index = cstate->input_buf_len = 0;
+
+ if (!cstate->opts.binary && cstate->need_transcoding)
+ {
+ cstate->raw_buf = palloc(RAW_BUF_SIZE);
+ cstate->raw_buf_index = cstate->raw_buf_len = 0;
}
/* Assign range table, we'll need it in CopyFrom. */
diff --git a/src/backend/commands/copyfromparse.c b/src/backend/commands/copyfromparse.c
index 4c74067f849..03d1c621792 100644
--- a/src/backend/commands/copyfromparse.c
+++ b/src/backend/commands/copyfromparse.c
@@ -3,6 +3,48 @@
* copyfromparse.c
* Parse CSV/text/binary format for COPY FROM.
*
+ * This file contains routines to parse the text, CSV and binary input
+ * formats. The main entry point is NextCopyFrom(), which parses the
+ * next input line and returns it as Datums.
+ *
+ * In text/CSV mode, the parsing happens in multiple stages:
+ *
+ * [data source] --> raw_buf --> input_buf --> line_buf --> attribute_buf
+ * 1. 2. 3. 4.
+ *
+ * 1. CopyLoadRawBuf() reads raw data from the input file or client, and
+ * places it into 'raw_buf'.
+ *
+ * 2. CopyLoadInputBufText() calls the encoding conversion function to
+ * convert the data in 'raw_buf' from client to server encoding, placing the
+ * converted result in 'input_buf'.
+ *
+ * 3. CopyReadLine() parses the data in 'input_buf', one line at a time.
+ * It is responsible for finding the next newline marker, taking quote and
+ * escape characters into account according to the COPY options. The line
+ * is copied into 'line_buf', with quotes and escape characters still intact.
+ *
+ * 4. CopyReadAttributesText/CSV() function takes the input line from
+ * 'line_buf', and splits it into fields, unescaping the data as required.
+ * The fields are stored in 'attribute_buf', and 'raw_fields' array holds
+ * pointers to each field.
+ *
+ * If encoding conversion is not required, a shortcut is taken in step 2
+ * to avoid copying the raw data unnecessarily. The 'input_buf' pointer is
+ * set to point directly to 'raw_buf', so that CopyLoadRawBuf() loads the
+ * raw data directly into 'input_buf'. CopyLoadInputBufText() then merely
+ * validates that the data is valid in the current encoding.
+ *
+ * In binary mode, the pipeline is much simpler. Input is loaded directly
+ * into 'input_buf', and encoding conversion is done in the datatype-specific
+ * receive functions, if required. 'line_buf' is not used, but
+ * 'attribute_buf' is used as a temporary buffer to hold one attribute's data
+ * when it's passed the receive function.
+ *
+ * input_buf is always 64 kB in size. 'raw_buf' is also 64 kB, if encoding
+ * conversion is required. 'line_buf' and 'attribute_buf' are expanded on
+ * demand, to hold the longest line encountered so far.
+ *
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
@@ -35,7 +77,7 @@
#define OCTVALUE(c) ((c) - '0')
/*
- * These macros centralize code used to process line_buf and raw_buf buffers.
+ * These macros centralize code used to process line_buf and input_buf buffers.
* They are macros because they often do continue/break control and to avoid
* function call overhead in tight COPY loops.
*
@@ -53,9 +95,9 @@
#define IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(extralen) \
if (1) \
{ \
- if (raw_buf_ptr + (extralen) >= copy_buf_len && !hit_eof) \
+ if (input_buf_ptr + (extralen) >= copy_buf_len && !hit_eof) \
{ \
- raw_buf_ptr = prev_raw_ptr; /* undo fetch */ \
+ input_buf_ptr = prev_raw_ptr; /* undo fetch */ \
need_data = true; \
continue; \
} \
@@ -65,10 +107,10 @@ if (1) \
#define IF_NEED_REFILL_AND_EOF_BREAK(extralen) \
if (1) \
{ \
- if (raw_buf_ptr + (extralen) >= copy_buf_len && hit_eof) \
+ if (input_buf_ptr + (extralen) >= copy_buf_len && hit_eof) \
{ \
if (extralen) \
- raw_buf_ptr = copy_buf_len; /* consume the partial character */ \
+ input_buf_ptr = copy_buf_len; /* consume the partial character */ \
/* backslash just before EOF, treat as data char */ \
result = true; \
break; \
@@ -77,17 +119,17 @@ if (1) \
/*
* Transfer any approved data to line_buf; must do this to be sure
- * there is some room in raw_buf.
+ * there is some room in input_buf.
*/
#define REFILL_LINEBUF \
if (1) \
{ \
- if (raw_buf_ptr > cstate->raw_buf_index) \
+ if (input_buf_ptr > cstate->input_buf_index) \
{ \
appendBinaryStringInfo(&cstate->line_buf, \
- cstate->raw_buf + cstate->raw_buf_index, \
- raw_buf_ptr - cstate->raw_buf_index); \
- cstate->raw_buf_index = raw_buf_ptr; \
+ cstate->input_buf + cstate->input_buf_index, \
+ input_buf_ptr - cstate->input_buf_index); \
+ cstate->input_buf_index = input_buf_ptr; \
} \
} else ((void) 0)
@@ -95,7 +137,7 @@ if (1) \
#define NO_END_OF_COPY_GOTO \
if (1) \
{ \
- raw_buf_ptr = prev_raw_ptr + 1; \
+ input_buf_ptr = prev_raw_ptr + 1; \
goto not_end_of_copy; \
} else ((void) 0)
@@ -118,7 +160,8 @@ static int CopyGetData(CopyFromState cstate, void *databuf,
int minread, int maxread);
static inline bool CopyGetInt32(CopyFromState cstate, int32 *val);
static inline bool CopyGetInt16(CopyFromState cstate, int16 *val);
-static bool CopyLoadRawBuf(CopyFromState cstate);
+static bool CopyLoadInputBufText(CopyFromState cstate);
+static bool CopyLoadInputBufBinary(CopyFromState cstate);
static int CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes);
void
@@ -359,42 +402,286 @@ CopyGetInt16(CopyFromState cstate, int16 *val)
return true;
}
+/*
+ * Perform encoding conversion on data in 'raw_buf', writing the converted
+ * data into 'input_buf'.
+ *
+ * On entry, there must be some data to convert in 'raw_buf'.
+ */
+static void
+CopyConvertBuf(CopyFromState cstate)
+{
+ int convertedbytes;
+ unsigned char *src;
+ int srclen;
+ unsigned char *dst;
+ int dstlen;
+
+ Assert(cstate->raw_buf_len > 0);
+ /*
+ * we assume that the caller has moved any remaining data in the
+ * buffer to the beginning.
+ */
+ Assert(cstate->input_buf_index == 0);
+
+ src = (unsigned char *) cstate->raw_buf + cstate->raw_buf_index;
+ srclen = cstate->raw_buf_len - cstate->raw_buf_index;
+ dst = (unsigned char *) cstate->input_buf + cstate->input_buf_len;
+ dstlen = INPUT_BUF_SIZE - cstate->input_buf_len + 1;
+
+ /*
+ * Do the conversion. This might stop short, if there is an invalid byte
+ * sequence in the input. We'll convert as much as we can in that case.
+ *
+ * Note: Even if we hit an invalid byte sequence, we don't report the error
+ * until all the valid bytes have been consumed. The input might contain
+ * an end-of-input marker (\.), and we don't want to report an error if
+ * the invalid byte sequence is after the end-of-input marker. We might
+ * unnecessarily convert some data after the end-of-input marker as long
+ * as it's valid for the encoding, but that's harmless.
+ */
+ convertedbytes = pg_do_encoding_conversion_buf(cstate->conversion_proc,
+ cstate->file_encoding,
+ GetDatabaseEncoding(),
+ src, srclen,
+ dst, dstlen,
+ true);
+ if (convertedbytes == 0)
+ {
+ /*
+ * No more valid input in the buffer, and we have hit an invalid or
+ * untranslatable byte sequence. Call the conversion function again,
+ * with noError=false, to let it throw an appropriate error.
+ */
+ (void) pg_do_encoding_conversion_buf(cstate->conversion_proc,
+ cstate->file_encoding,
+ GetDatabaseEncoding(),
+ src, srclen,
+ dst, dstlen,
+ false);
+ /*
+ * Should not get here, because if the input contained invalid data on the
+ * first call, the second pg_do_encoding_conversion_buf with noError = false
+ * should've reported an error. But just in case the conversion function
+ * messsed up.
+ */
+ elog(ERROR, "encoding conversion failed without error");
+ }
+ cstate->raw_buf_index += convertedbytes;
+ cstate->input_buf_len += strlen((char *) dst);
+}
/*
- * CopyLoadRawBuf loads some more data into raw_buf
+ * Load more data from data source to raw_buf.
*
- * Returns true if able to obtain at least one more byte, else false.
+ * Returns true if at least one more byte was loaded, false means EOF was reached.
*
* If RAW_BUF_BYTES(cstate) > 0, the unprocessed bytes are moved to the start
- * of the buffer and then we load more data after that. This case occurs only
- * when a multibyte character crosses a bufferload boundary.
+ * of the buffer and then we load more data after that.
*/
static bool
CopyLoadRawBuf(CopyFromState cstate)
{
- int nbytes = RAW_BUF_BYTES(cstate);
+ int nbytes;
int inbytes;
+ /*
+ * If encoding conversion is not required, raw_buf and input_buf point
+ * to the same buffer. Their len/index should agree, too, otherwise
+ * we are confused.
+ */
+ if (cstate->raw_buf == cstate->input_buf)
+ {
+ Assert(!cstate->need_transcoding);
+ Assert(cstate->raw_buf_index == cstate->input_buf_index);
+ Assert(cstate->input_buf_len <= cstate->raw_buf_len);
+ }
+
/* Copy down the unprocessed data if any. */
- if (nbytes > 0)
+ nbytes = RAW_BUF_BYTES(cstate);
+ if (nbytes > 0 && cstate->raw_buf_index > 0)
memmove(cstate->raw_buf, cstate->raw_buf + cstate->raw_buf_index,
nbytes);
+ cstate->raw_buf_len -= cstate->raw_buf_index;
+ cstate->raw_buf_index = 0;
+
+ /*
+ * If raw_buf and input_buf are in fact the same buffer, adjust the
+ * input_buf variables, too.
+ */
+ if (cstate->raw_buf == cstate->input_buf)
+ {
+ cstate->input_buf_len -= cstate->input_buf_index;
+ cstate->input_buf_index = 0;
+ }
+
+ /* Load more data */
+ inbytes = CopyGetData(cstate, cstate->raw_buf + cstate->raw_buf_len,
+ 1, RAW_BUF_SIZE - cstate->raw_buf_len);
+ cstate->raw_buf_len += inbytes;
+
+ cstate->bytes_processed += inbytes;
+ pgstat_progress_update_param(PROGRESS_COPY_BYTES_PROCESSED, cstate->bytes_processed);
+
+ return (inbytes > 0);
+}
+
+/*
+ * CopyLoadInputBuf loads some more data into input_buf
+ *
+ * Returns true if able to obtain at least one more byte, else false.
+ *
+ * If INPUT_BUF_BYTES(cstate) > 0, the unprocessed bytes are moved to the start
+ * of the buffer and then we load more data after that.
+ */
+static bool
+CopyLoadInputBufText(CopyFromState cstate)
+{
+ int nbytes;
+
+ if (!cstate->need_transcoding)
+ {
+ /*
+ * If the file and server encoding are the same, no encoding conversion
+ * is required, and we can load the input data directly into 'input_buf'.
+ * However, we still need to verify that the input is valid for the encoding.
+ *
+ * FIXME: for single-byte encoding, the verification only needs to check
+ * that the input doesn't contain any zero bytes. Could we skip that
+ * altogether?
+ *
+ * On entry, input_buf_len indicates how many bytes in the buffer have
+ * already been validated. raw_buf_len can be larger, if there was an
+ * incomplete multi-byte character at the bufferload boundary, or if the
+ * input contains an invalid character.
+ */
+ for (;;)
+ {
+ int verified_bytes = INPUT_BUF_BYTES(cstate);
+ int unverified_bytes = cstate->raw_buf_len - cstate->input_buf_len;
+ int nvalidated;
+
+ /* Load more bytes to the buffer */
+ cstate->raw_buf_index = cstate->input_buf_index;
+ cstate->raw_buf = cstate->input_buf;
+ if (!CopyLoadRawBuf(cstate))
+ {
+ /*
+ * EOF reached. If we have any unverified bytes left, it means
+ * that there was an incomplete multi-byte character at the end.
+ */
+ if (unverified_bytes > 0)
+ report_invalid_encoding(cstate->file_encoding,
+ cstate->raw_buf + verified_bytes,
+ unverified_bytes);
- inbytes = CopyGetData(cstate, cstate->raw_buf + nbytes,
- 1, RAW_BUF_SIZE - nbytes);
+ /* truly hit EOF */
+ return false;
+ }
+ Assert(cstate->raw_buf_index == 0);
+ Assert(cstate->input_buf_index == 0);
+ unverified_bytes = cstate->raw_buf_len - verified_bytes;
+ Assert(unverified_bytes > 0);
+
+ /* Verify the new data (including any unverified bytes from previous round) */
+ nvalidated = pg_encoding_verifymbstr(cstate->file_encoding,
+ cstate->raw_buf + verified_bytes,
+ unverified_bytes);
+ if (nvalidated == 0)
+ {
+ /*
+ * No valid characters in the buffer. It could be because
+ * there are only few bytes in the buffer, and they don't form
+ * any whole characters. In that case, load more data. But if
+ * we have enough data, then it must be an invalid byte
+ * sequence.
+ */
+ if (unverified_bytes < pg_database_encoding_max_length())
+ continue;
+ else
+ report_invalid_encoding(cstate->file_encoding, cstate->raw_buf + verified_bytes,
+ unverified_bytes);
+ }
+ verified_bytes += nvalidated;
+
+ cstate->input_buf_index = 0;
+ cstate->input_buf_len = verified_bytes;
+ return true;
+ }
+ }
+ else
+ {
+ /*
+ * Encoding conversion is needed. First, copy down the unprocessed data
+ * if any.
+ */
+ nbytes = INPUT_BUF_BYTES(cstate);
+ if (nbytes > 0 && cstate->input_buf_index > 0)
+ memmove(cstate->input_buf, cstate->input_buf + cstate->input_buf_index,
+ nbytes);
+ cstate->input_buf_index = 0;
+ cstate->input_buf_len = nbytes;
+
+ for (;;)
+ {
+ /* If we still have a good amount of unconverted data left, convert it. */
+ nbytes = cstate->raw_buf_len - cstate->raw_buf_index;
+ if (nbytes >= MAX_CONVERSION_GROWTH)
+ {
+ CopyConvertBuf(cstate);
+ break;
+ }
+
+ /* Load more bytes to the raw buffer */
+ if (!CopyLoadRawBuf(cstate))
+ {
+ /* Hit EOF. If we have any unconverted bytes left, convert them now */
+ if (cstate->raw_buf_index < cstate->raw_buf_len)
+ {
+ CopyConvertBuf(cstate);
+ break;
+ }
+
+ /*
+ * No more input data, and no unconverted data remain in raw_buf. Report
+ * the EOF to the caller
+ */
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static bool
+CopyLoadInputBufBinary(CopyFromState cstate)
+{
+ int nbytes = INPUT_BUF_BYTES(cstate);
+ int inbytes;
+
+ /* Copy down the unprocessed data if any. */
+ if (nbytes > 0)
+ memmove(cstate->input_buf, cstate->input_buf + cstate->input_buf_index,
+ nbytes);
+
+ inbytes = CopyGetData(cstate, cstate->input_buf + nbytes,
+ 1, INPUT_BUF_SIZE - nbytes);
nbytes += inbytes;
- cstate->raw_buf[nbytes] = '\0';
- cstate->raw_buf_index = 0;
- cstate->raw_buf_len = nbytes;
+ cstate->input_buf[nbytes] = '\0';
+ cstate->input_buf_index = 0;
+ cstate->input_buf_len = nbytes;
+
cstate->bytes_processed += nbytes;
pgstat_progress_update_param(PROGRESS_COPY_BYTES_PROCESSED, cstate->bytes_processed);
+
return (inbytes > 0);
}
/*
* CopyReadBinaryData
*
- * Reads up to 'nbytes' bytes from cstate->copy_file via cstate->raw_buf
+ * Reads up to 'nbytes' bytes from cstate->copy_file via cstate->input_buf
* and writes them to 'dest'. Returns the number of bytes read (which
* would be less than 'nbytes' only if we reach EOF).
*/
@@ -403,11 +690,11 @@ CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes)
{
int copied_bytes = 0;
- if (RAW_BUF_BYTES(cstate) >= nbytes)
+ if (INPUT_BUF_BYTES(cstate) >= nbytes)
{
/* Enough bytes are present in the buffer. */
- memcpy(dest, cstate->raw_buf + cstate->raw_buf_index, nbytes);
- cstate->raw_buf_index += nbytes;
+ memcpy(dest, cstate->input_buf + cstate->input_buf_index, nbytes);
+ cstate->input_buf_index += nbytes;
copied_bytes = nbytes;
}
else
@@ -421,16 +708,16 @@ CopyReadBinaryData(CopyFromState cstate, char *dest, int nbytes)
int copy_bytes;
/* Load more data if buffer is empty. */
- if (RAW_BUF_BYTES(cstate) == 0)
+ if (INPUT_BUF_BYTES(cstate) == 0)
{
- if (!CopyLoadRawBuf(cstate))
+ if (!CopyLoadInputBufBinary(cstate))
break; /* EOF */
}
/* Transfer some bytes. */
- copy_bytes = Min(nbytes - copied_bytes, RAW_BUF_BYTES(cstate));
- memcpy(dest, cstate->raw_buf + cstate->raw_buf_index, copy_bytes);
- cstate->raw_buf_index += copy_bytes;
+ copy_bytes = Min(nbytes - copied_bytes, INPUT_BUF_BYTES(cstate));
+ memcpy(dest, cstate->input_buf + cstate->input_buf_index, copy_bytes);
+ cstate->input_buf_index += copy_bytes;
dest += copy_bytes;
copied_bytes += copy_bytes;
} while (copied_bytes < nbytes);
@@ -699,9 +986,6 @@ CopyReadLine(CopyFromState cstate)
resetStringInfo(&cstate->line_buf);
cstate->line_buf_valid = true;
- /* Mark that encoding conversion hasn't occurred yet */
- cstate->line_buf_converted = false;
-
/* Parse data and transfer into line_buf */
result = CopyReadLineText(cstate);
@@ -714,10 +998,13 @@ CopyReadLine(CopyFromState cstate)
*/
if (cstate->copy_src == COPY_NEW_FE)
{
+ int inbytes;
+
do
{
- cstate->raw_buf_index = cstate->raw_buf_len;
- } while (CopyLoadRawBuf(cstate));
+ inbytes = CopyGetData(cstate, cstate->input_buf,
+ 1, INPUT_BUF_SIZE);
+ } while (inbytes > 0);
}
}
else
@@ -754,26 +1041,6 @@ CopyReadLine(CopyFromState cstate)
}
}
- /* Done reading the line. Convert it to server encoding. */
- if (cstate->need_transcoding)
- {
- char *cvt;
-
- cvt = pg_any_to_server(cstate->line_buf.data,
- cstate->line_buf.len,
- cstate->file_encoding);
- if (cvt != cstate->line_buf.data)
- {
- /* transfer converted data back to line_buf */
- resetStringInfo(&cstate->line_buf);
- appendBinaryStringInfo(&cstate->line_buf, cvt, strlen(cvt));
- pfree(cvt);
- }
- }
-
- /* Now it's safe to use the buffer in error messages */
- cstate->line_buf_converted = true;
-
return result;
}
@@ -783,13 +1050,12 @@ CopyReadLine(CopyFromState cstate)
static bool
CopyReadLineText(CopyFromState cstate)
{
- char *copy_raw_buf;
- int raw_buf_ptr;
+ char *copy_input_buf;
+ int input_buf_ptr;
int copy_buf_len;
bool need_data = false;
bool hit_eof = false;
bool result = false;
- char mblen_str[2];
/* CSV variables */
bool first_char_in_line = true;
@@ -807,8 +1073,6 @@ CopyReadLineText(CopyFromState cstate)
escapec = '\0';
}
- mblen_str[1] = '\0';
-
/*
* The objective of this loop is to transfer the entire next input line
* into line_buf. Hence, we only care for detecting newlines (\r and/or
@@ -821,18 +1085,25 @@ CopyReadLineText(CopyFromState cstate)
* These four characters, and the CSV escape and quote characters, are
* assumed the same in frontend and backend encodings.
*
- * For speed, we try to move data from raw_buf to line_buf in chunks
- * rather than one character at a time. raw_buf_ptr points to the next
- * character to examine; any characters from raw_buf_index to raw_buf_ptr
+ * The input has already been converted to the database encoding. All
+ * supported server encodings have the property that all bytes in a
+ * multi-byte sequence have the high bit set, so a multibyte character
+ * cannot contain any newline or escape characters embedded in the
+ * multibyte sequence. Therefore, we can process the input byte-by-byte,
+ * regardless of the encoding.
+ *
+ * For speed, we try to move data from input_buf to line_buf in chunks
+ * rather than one character at a time. input_buf_ptr points to the next
+ * character to examine; any characters from input_buf_index to input_buf_ptr
* have been determined to be part of the line, but not yet transferred to
* line_buf.
*
- * For a little extra speed within the loop, we copy raw_buf and
- * raw_buf_len into local variables.
+ * For a little extra speed within the loop, we copy input_buf and
+ * input_buf_len into local variables.
*/
- copy_raw_buf = cstate->raw_buf;
- raw_buf_ptr = cstate->raw_buf_index;
- copy_buf_len = cstate->raw_buf_len;
+ copy_input_buf = cstate->input_buf;
+ input_buf_ptr = cstate->input_buf_index;
+ copy_buf_len = cstate->input_buf_len;
for (;;)
{
@@ -849,18 +1120,18 @@ CopyReadLineText(CopyFromState cstate)
* cstate->copy_src != COPY_OLD_FE, but it hardly seems worth it,
* considering the size of the buffer.
*/
- if (raw_buf_ptr >= copy_buf_len || need_data)
+ if (input_buf_ptr >= copy_buf_len || need_data)
{
REFILL_LINEBUF;
/*
* Try to read some more data. This will certainly reset
- * raw_buf_index to zero, and raw_buf_ptr must go with it.
+ * input_buf_index to zero, and input_buf_ptr must go with it.
*/
- if (!CopyLoadRawBuf(cstate))
+ if (!CopyLoadInputBufText(cstate))
hit_eof = true;
- raw_buf_ptr = 0;
- copy_buf_len = cstate->raw_buf_len;
+ input_buf_ptr = 0;
+ copy_buf_len = cstate->input_buf_len;
/*
* If we are completely out of data, break out of the loop,
@@ -875,8 +1146,8 @@ CopyReadLineText(CopyFromState cstate)
}
/* OK to fetch a character */
- prev_raw_ptr = raw_buf_ptr;
- c = copy_raw_buf[raw_buf_ptr++];
+ prev_raw_ptr = input_buf_ptr;
+ c = copy_input_buf[input_buf_ptr++];
if (cstate->opts.csv_mode)
{
@@ -930,16 +1201,16 @@ CopyReadLineText(CopyFromState cstate)
* If need more data, go back to loop top to load it.
*
* Note that if we are at EOF, c will wind up as '\0' because
- * of the guaranteed pad of raw_buf.
+ * of the guaranteed pad of input_buf.
*/
IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
/* get next char */
- c = copy_raw_buf[raw_buf_ptr];
+ c = copy_input_buf[input_buf_ptr];
if (c == '\n')
{
- raw_buf_ptr++; /* eat newline */
+ input_buf_ptr++; /* eat newline */
cstate->eol_type = EOL_CRNL; /* in case not set yet */
}
else
@@ -1009,11 +1280,11 @@ CopyReadLineText(CopyFromState cstate)
* through and continue processing for file encoding.
* -----
*/
- c2 = copy_raw_buf[raw_buf_ptr];
+ c2 = copy_input_buf[input_buf_ptr];
if (c2 == '.')
{
- raw_buf_ptr++; /* consume the '.' */
+ input_buf_ptr++; /* consume the '.' */
/*
* Note: if we loop back for more data here, it does not
@@ -1025,7 +1296,7 @@ CopyReadLineText(CopyFromState cstate)
/* Get the next character */
IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
/* if hit_eof, c2 will become '\0' */
- c2 = copy_raw_buf[raw_buf_ptr++];
+ c2 = copy_input_buf[input_buf_ptr++];
if (c2 == '\n')
{
@@ -1050,7 +1321,7 @@ CopyReadLineText(CopyFromState cstate)
/* Get the next character */
IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(0);
/* if hit_eof, c2 will become '\0' */
- c2 = copy_raw_buf[raw_buf_ptr++];
+ c2 = copy_input_buf[input_buf_ptr++];
if (c2 != '\r' && c2 != '\n')
{
@@ -1075,11 +1346,11 @@ CopyReadLineText(CopyFromState cstate)
* Transfer only the data before the \. into line_buf, then
* discard the data and the \. sequence.
*/
- if (prev_raw_ptr > cstate->raw_buf_index)
+ if (prev_raw_ptr > cstate->input_buf_index)
appendBinaryStringInfo(&cstate->line_buf,
- cstate->raw_buf + cstate->raw_buf_index,
- prev_raw_ptr - cstate->raw_buf_index);
- cstate->raw_buf_index = raw_buf_ptr;
+ cstate->input_buf + cstate->input_buf_index,
+ prev_raw_ptr - cstate->input_buf_index);
+ cstate->input_buf_index = input_buf_ptr;
result = true; /* report EOF */
break;
}
@@ -1096,7 +1367,7 @@ CopyReadLineText(CopyFromState cstate)
* character after the backslash just like a normal character,
* so we don't increment in those cases.
*/
- raw_buf_ptr++;
+ input_buf_ptr++;
}
/*
@@ -1106,30 +1377,6 @@ CopyReadLineText(CopyFromState cstate)
* value, while in non-CSV mode, \. cannot be a data value.
*/
not_end_of_copy:
-
- /*
- * Process all bytes of a multi-byte character as a group.
- *
- * We only support multi-byte sequences where the first byte has the
- * high-bit set, so as an optimization we can avoid this block
- * entirely if it is not set.
- */
- if (cstate->encoding_embeds_ascii && IS_HIGHBIT_SET(c))
- {
- int mblen;
-
- /*
- * It is enough to look at the first byte in all our encodings, to
- * get the length. (GB18030 is a bit special, but still works for
- * our purposes; see comment in pg_gb18030_mblen())
- */
- mblen_str[0] = c;
- mblen = pg_encoding_mblen(cstate->file_encoding, mblen_str);
-
- IF_NEED_REFILL_AND_NOT_EOF_CONTINUE(mblen - 1);
- IF_NEED_REFILL_AND_EOF_BREAK(mblen - 1);
- raw_buf_ptr += mblen - 1;
- }
first_char_in_line = false;
} /* end of outer loop */
diff --git a/src/include/commands/copyfrom_internal.h b/src/include/commands/copyfrom_internal.h
index e37942df391..86c92394a09 100644
--- a/src/include/commands/copyfrom_internal.h
+++ b/src/include/commands/copyfrom_internal.h
@@ -53,17 +53,6 @@ typedef enum CopyInsertMethod
/*
* This struct contains all the state variables used throughout a COPY FROM
* operation.
- *
- * Multi-byte encodings: all supported client-side encodings encode multi-byte
- * characters by having the first byte's high bit set. Subsequent bytes of the
- * character can have the high bit not set. When scanning data in such an
- * encoding to look for a match to a single-byte (ie ASCII) character, we must
- * use the full pg_encoding_mblen() machinery to skip over multibyte
- * characters, else we might find a false match to a trailing byte. In
- * supported server encodings, there is no possibility of a false match, and
- * it's faster to make useless comparisons to trailing bytes than it is to
- * invoke pg_encoding_mblen() to skip over them. encoding_embeds_ascii is true
- * when we have to do it the hard way.
*/
typedef struct CopyFromStateData
{
@@ -77,7 +66,7 @@ typedef struct CopyFromStateData
EolType eol_type; /* EOL type of input */
int file_encoding; /* file or remote side's character encoding */
bool need_transcoding; /* file encoding diff from server? */
- bool encoding_embeds_ascii; /* ASCII can be non-first byte? */
+ Oid conversion_proc;
/* parameters from the COPY command */
Relation rel; /* relation to copy from */
@@ -132,31 +121,45 @@ typedef struct CopyFromStateData
/*
* Similarly, line_buf holds the whole input line being processed. The
- * input cycle is first to read the whole line into line_buf, convert it
- * to server encoding there, and then extract the individual attribute
- * fields into attribute_buf. line_buf is preserved unmodified so that we
- * can display it in error messages if appropriate. (In binary mode,
- * line_buf is not used.)
+ * input cycle is first to read the whole line into line_buf, and then
+ * extract the individual attribute fields into attribute_buf. line_buf
+ * is preserved unmodified so that we can display it in error messages
+ * if appropriate. (In binary mode, line_buf is not used.)
*/
StringInfoData line_buf;
- bool line_buf_converted; /* converted to server encoding? */
bool line_buf_valid; /* contains the row being processed? */
/*
- * Finally, raw_buf holds raw data read from the data source (file or
- * client connection). In text mode, CopyReadLine parses this data
+ * input_buf holds input data, already converted to database encoding.
+ *
+ * In text mode, CopyReadLine parses this data
* sufficiently to locate line boundaries, then transfers the data to
- * line_buf and converts it. In binary mode, CopyReadBinaryData fetches
+ * line_buf. In binary mode, CopyReadBinaryData fetches
* appropriate amounts of data from this buffer. In both modes, we
- * guarantee that there is a \0 at raw_buf[raw_buf_len].
+ * guarantee that there is a \0 at input_buf[input_buf_len]. FIXME: do we still?
*/
-#define RAW_BUF_SIZE 65536 /* we palloc RAW_BUF_SIZE+1 bytes */
+#define INPUT_BUF_SIZE 65536 /* we palloc INPUT_BUF_SIZE+1 bytes */
+ char *input_buf;
+ int input_buf_index; /* next byte to process */
+ int input_buf_len; /* total # of bytes stored */
+ /* Shorthand for number of unconsumed bytes available in input_buf */
+#define INPUT_BUF_BYTES(cstate) ((cstate)->input_buf_len - (cstate)->input_buf_index)
+
+ /*
+ * raw_buf holds raw input data read from the data source (file or
+ * client connection), not yet converted to the database encoding.
+ *
+ * If the encoding conversion is not required, the input data is read
+ * directly into 'input_buf', and raw_buf is not used.
+ */
+#define RAW_BUF_SIZE 65536 /* allocated size of the buffer */
char *raw_buf;
int raw_buf_index; /* next byte to process */
- int raw_buf_len; /* total # of bytes stored */
- uint64 bytes_processed;/* number of bytes processed so far */
+ int raw_buf_len; /* total # of bytes stored */
/* Shorthand for number of unconsumed bytes available in raw_buf */
#define RAW_BUF_BYTES(cstate) ((cstate)->raw_buf_len - (cstate)->raw_buf_index)
+
+ uint64 bytes_processed; /* number of bytes processed so far */
} CopyFromStateData;
extern void ReceiveCopyBegin(CopyFromState cstate);
diff --git a/src/test/regress/expected/copycorners.out b/src/test/regress/expected/copycorners.out
new file mode 100644
index 00000000000..ac3a6fe022b
--- /dev/null
+++ b/src/test/regress/expected/copycorners.out
@@ -0,0 +1,202 @@
+create temp table copytest (
+ a text,
+ b text,
+ c text);
+create extension plperlu;
+create function write_test_file(content text) returns void language plperlu as
+$$
+use strict;
+use warnings;
+
+open(FH, '>', '/tmp/copycorners.data') or die $!;
+print FH $_[0];
+close(FH);
+
+$$;
+create function copytest(copyoptions text, content text) returns setof copytest language plpgsql as
+$$
+begin
+ truncate copytest;
+ perform write_test_file($2);
+
+ execute 'copy copytest from ''/tmp/copycorners.data''' || copyoptions;
+ return query select * from copytest;
+end;
+$$;
+-- Basic tests. Not very interesting but see that write_test_file() works.
+select * from copytest('',
+$$a b c$$
+);
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+select * from copytest('',
+$$a b c
+$$
+);
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+--
+-- Test EOL detection
+--
+select * from copytest('', E'a b c\nd e f\n'); -- ok
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+select * from copytest('', E'a b c\rd e f\r'); -- ok
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+select * from copytest('', E'a b c\r\nd e f\r\n'); -- ok
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+select * from copytest('', E'a b c\nd e f\r'); -- mismatch
+ERROR: literal carriage return found in data
+HINT: Use "\r" to represent carriage return.
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\rd e f\n'); -- mismatch
+ERROR: literal newline found in data
+HINT: Use "\n" to represent newline.
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\r\nd e f\n'); -- mismatch
+ERROR: literal newline found in data
+HINT: Use "\n" to represent newline.
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\r\nd e f\r'); -- mismatch
+ERROR: literal carriage return found in data
+HINT: Use "\r" to represent carriage return.
+CONTEXT: COPY copytest, line 2: "d e f"
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+--
+-- Test end-of-copy markers at different locations.
+--
+select * from copytest('', E'a b c\\.');
+ERROR: end-of-copy marker corrupt
+CONTEXT: COPY copytest, line 1: "a b c"
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\\.\n');
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+select * from copytest('', E'a b c\n\n\\.');
+ERROR: missing data for column "b"
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\n\n\\.\n');
+ERROR: missing data for column "b"
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+-- \. on a line of its own, with garbage after it
+select * from copytest('', E'a b c\n\\.\ngarbage');
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+-- \. at beginning of line, with garbage after it
+select * from copytest('', E'a b c\n\\.garbage');
+ERROR: end-of-copy marker corrupt
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+-- \. in the middle of file, and garbage after it.
+select * from copytest('', E'a b\\.garbage');
+ERROR: end-of-copy marker corrupt
+CONTEXT: COPY copytest, line 1: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+--
+-- Test end-of-copy markers with different EOLs
+--
+select * from copytest('', E'a b c\nd e f\\.\n');
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+select * from copytest('', E'a b c\rd e f\\.\r');
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+select * from copytest('', E'a b c\r\nd e f\\.\r\n');
+ a | b | c
+---+---+---
+ a | b | c
+ d | e | f
+(2 rows)
+
+-- mismatch between EOL style and EOL after \.
+select * from copytest('', E'a b c\na b c\\.\r');
+ERROR: end-of-copy marker does not match previous newline style
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\ra b c\\.\n');
+ERROR: end-of-copy marker does not match previous newline style
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\r\na b c\\.\n');
+ERROR: end-of-copy marker does not match previous newline style
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\na b c\\.\r\n');
+ERROR: end-of-copy marker does not match previous newline style
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+-- end-of-copy marker on first line, with different EOL styles
+select * from copytest('', E'a b c\\.');
+ERROR: end-of-copy marker corrupt
+CONTEXT: COPY copytest, line 1: "a b c"
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
+select * from copytest('', E'a b c\\.\n');
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+select * from copytest('', E'a b c\\.\r');
+ a | b | c
+---+---+---
+ a | b | c
+(1 row)
+
+select * from copytest('', E'a b c\\.\r\n');
+ERROR: missing data for column "b"
+CONTEXT: COPY copytest, line 2: ""
+SQL statement "copy copytest from '/tmp/copycorners.data'"
+PL/pgSQL function copytest(text,text) line 6 at EXECUTE
diff --git a/src/test/regress/sql/copycorners.sql b/src/test/regress/sql/copycorners.sql
new file mode 100644
index 00000000000..c5960bdceab
--- /dev/null
+++ b/src/test/regress/sql/copycorners.sql
@@ -0,0 +1,90 @@
+create temp table copytest (
+ a text,
+ b text,
+ c text);
+
+create extension plperlu;
+
+create function write_test_file(content text) returns void language plperlu as
+$$
+use strict;
+use warnings;
+
+open(FH, '>', '/tmp/copycorners.data') or die $!;
+print FH $_[0];
+close(FH);
+
+$$;
+
+create function copytest(copyoptions text, content text) returns setof copytest language plpgsql as
+$$
+begin
+ truncate copytest;
+ perform write_test_file($2);
+
+ execute 'copy copytest from ''/tmp/copycorners.data''' || copyoptions;
+ return query select * from copytest;
+end;
+$$;
+
+-- Basic tests. Not very interesting but see that write_test_file() works.
+select * from copytest('',
+$$a b c$$
+);
+
+select * from copytest('',
+$$a b c
+$$
+);
+
+--
+-- Test EOL detection
+--
+select * from copytest('', E'a b c\nd e f\n'); -- ok
+select * from copytest('', E'a b c\rd e f\r'); -- ok
+select * from copytest('', E'a b c\r\nd e f\r\n'); -- ok
+select * from copytest('', E'a b c\nd e f\r'); -- mismatch
+select * from copytest('', E'a b c\rd e f\n'); -- mismatch
+select * from copytest('', E'a b c\r\nd e f\n'); -- mismatch
+select * from copytest('', E'a b c\r\nd e f\r'); -- mismatch
+
+--
+-- Test end-of-copy markers at different locations.
+--
+
+select * from copytest('', E'a b c\\.');
+
+select * from copytest('', E'a b c\\.\n');
+
+select * from copytest('', E'a b c\n\n\\.');
+
+select * from copytest('', E'a b c\n\n\\.\n');
+
+-- \. on a line of its own, with garbage after it
+select * from copytest('', E'a b c\n\\.\ngarbage');
+
+-- \. at beginning of line, with garbage after it
+select * from copytest('', E'a b c\n\\.garbage');
+
+-- \. in the middle of file, and garbage after it.
+select * from copytest('', E'a b\\.garbage');
+
+
+--
+-- Test end-of-copy markers with different EOLs
+--
+select * from copytest('', E'a b c\nd e f\\.\n');
+select * from copytest('', E'a b c\rd e f\\.\r');
+select * from copytest('', E'a b c\r\nd e f\\.\r\n');
+
+-- mismatch between EOL style and EOL after \.
+select * from copytest('', E'a b c\na b c\\.\r');
+select * from copytest('', E'a b c\ra b c\\.\n');
+select * from copytest('', E'a b c\r\na b c\\.\n');
+select * from copytest('', E'a b c\na b c\\.\r\n');
+
+-- end-of-copy marker on first line, with different EOL styles
+select * from copytest('', E'a b c\\.');
+select * from copytest('', E'a b c\\.\n');
+select * from copytest('', E'a b c\\.\r');
+select * from copytest('', E'a b c\\.\r\n');
--
2.29.2
--------------39E46EF15EBFAA37D53332E5--
^ permalink raw reply [nested|flat] 5+ messages in thread
* Use pg_malloc macros in src/fe_utils
@ 2026-02-18 15:05 Henrik TJ <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Henrik TJ @ 2026-02-18 15:05 UTC (permalink / raw)
To: pgsql-hackers
Hi
Inspired by [1], I took a stab at converting src/fe_utils to the new
pg_malloc macros.
Some mostly useless metrics: 31/34 converted, 7 casts removed.
meson test looks good for me.
1. https://www.postgresql.org/message-id/flat/CAHut%2BPvpGPDLhkHAoxw_g3jdrYxA1m16a8uagbgH3TGWSKtXNQ%40m...
best regards, Henrik
From 6ad0e5be35029a1aa32452cfeba5fe0ec55b1f5d Mon Sep 17 00:00:00 2001
From: Henrik TJ <[email protected]>
Date: Fri, 13 Feb 2026 15:51:47 +0100
Subject: [PATCH] fe_utils: Use pg_malloc_object() and pg_malloc_array()
Use more high-level allocation routines in src/fe_utils.
Similar to 31d3847a37be and 6736dea14af
---
src/fe_utils/conditional.c | 4 ++--
src/fe_utils/print.c | 48 +++++++++++++++++++-------------------
src/fe_utils/psqlscan.l | 8 +++----
src/fe_utils/simple_list.c | 4 ++--
4 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/src/fe_utils/conditional.c b/src/fe_utils/conditional.c
index deba61e0d81..537c76ed3cd 100644
--- a/src/fe_utils/conditional.c
+++ b/src/fe_utils/conditional.c
@@ -17,7 +17,7 @@
ConditionalStack
conditional_stack_create(void)
{
- ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
+ ConditionalStack cstack = pg_malloc_object(ConditionalStackData);
cstack->head = NULL;
return cstack;
@@ -52,7 +52,7 @@ conditional_stack_destroy(ConditionalStack cstack)
void
conditional_stack_push(ConditionalStack cstack, ifState new_state)
{
- IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
+ IfStackElem *p = pg_malloc_object(IfStackElem);
p->if_state = new_state;
p->query_len = -1;
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index ef52cdee9b7..12d969e8666 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -344,7 +344,7 @@ format_numeric_locale(const char *my_str)
return pg_strdup(my_str);
new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
- new_str = pg_malloc(new_len + 1);
+ new_str = pg_malloc_array(char, (new_len + 1));
new_str_pos = 0;
int_len = integer_digits(my_str);
@@ -692,18 +692,18 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
if (cont->ncolumns > 0)
{
col_count = cont->ncolumns;
- width_header = pg_malloc0(col_count * sizeof(*width_header));
- width_average = pg_malloc0(col_count * sizeof(*width_average));
- max_width = pg_malloc0(col_count * sizeof(*max_width));
- width_wrap = pg_malloc0(col_count * sizeof(*width_wrap));
- max_nl_lines = pg_malloc0(col_count * sizeof(*max_nl_lines));
- curr_nl_line = pg_malloc0(col_count * sizeof(*curr_nl_line));
- col_lineptrs = pg_malloc0(col_count * sizeof(*col_lineptrs));
- max_bytes = pg_malloc0(col_count * sizeof(*max_bytes));
- format_buf = pg_malloc0(col_count * sizeof(*format_buf));
- header_done = pg_malloc0(col_count * sizeof(*header_done));
- bytes_output = pg_malloc0(col_count * sizeof(*bytes_output));
- wrap = pg_malloc0(col_count * sizeof(*wrap));
+ width_header = pg_malloc0_array(unsigned int, col_count);
+ width_average = pg_malloc0_array(unsigned int, col_count);
+ max_width = pg_malloc0_array(unsigned int, col_count);
+ width_wrap = pg_malloc0_array(unsigned int, col_count);
+ max_nl_lines = pg_malloc0_array(unsigned int, col_count);
+ curr_nl_line = pg_malloc0_array(unsigned int, col_count);
+ col_lineptrs = pg_malloc0_array(struct lineptr *, col_count);
+ max_bytes = pg_malloc0_array(unsigned int, col_count);
+ format_buf = pg_malloc0_array(unsigned char *, col_count);
+ header_done = pg_malloc0_array(bool, col_count);
+ bytes_output = pg_malloc0_array(int, col_count);
+ wrap = pg_malloc0_array(printTextLineWrap, col_count);
}
else
{
@@ -798,10 +798,10 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
for (i = 0; i < col_count; i++)
{
/* Add entry for ptr == NULL array termination */
- col_lineptrs[i] = pg_malloc0((max_nl_lines[i] + 1) *
- sizeof(**col_lineptrs));
+ col_lineptrs[i] = pg_malloc0_array(struct lineptr,
+ (max_nl_lines[i] + 1));
- format_buf[i] = pg_malloc(max_bytes[i] + 1);
+ format_buf[i] = pg_malloc_array(unsigned char, (max_bytes[i] + 1));
col_lineptrs[i]->ptr = format_buf[i];
}
@@ -1409,8 +1409,8 @@ print_aligned_vertical(const printTableContent *cont,
* We now have all the information we need to setup the formatting
* structures
*/
- dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
- hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
+ dlineptr = pg_malloc_array(struct lineptr, (dheight + 1));
+ hlineptr = pg_malloc_array(struct lineptr, (hheight + 1));
dlineptr->ptr = pg_malloc(dformatsize);
hlineptr->ptr = pg_malloc(hformatsize);
@@ -3198,7 +3198,7 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
content->ncolumns = ncolumns;
content->nrows = nrows;
- content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
+ content->headers = pg_malloc0_array(const char *, (ncolumns + 1));
total_cells = (uint64) ncolumns * nrows;
/* Catch possible overflow. Using >= here allows adding 1 below */
@@ -3209,12 +3209,12 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
SIZE_MAX / sizeof(*content->cells));
exit(EXIT_FAILURE);
}
- content->cells = pg_malloc0((total_cells + 1) * sizeof(*content->cells));
+ content->cells = pg_malloc0_array(const char *, (total_cells + 1));
content->cellmustfree = NULL;
content->footers = NULL;
- content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
+ content->aligns = pg_malloc0_array(char, (ncolumns + 1));
content->header = content->headers;
content->cell = content->cells;
@@ -3305,7 +3305,7 @@ printTableAddCell(printTableContent *const content, char *cell,
{
if (content->cellmustfree == NULL)
content->cellmustfree =
- pg_malloc0((total_cells + 1) * sizeof(bool));
+ pg_malloc0_array(bool, (total_cells + 1));
content->cellmustfree[content->cellsadded] = true;
}
@@ -3330,7 +3330,7 @@ printTableAddFooter(printTableContent *const content, const char *footer)
{
printTableFooter *f;
- f = pg_malloc0(sizeof(*f));
+ f = pg_malloc0_object(printTableFooter);
f->data = pg_strdup(footer);
if (content->footers == NULL)
@@ -3477,7 +3477,7 @@ count_table_lines(const printTableContent *cont,
* Scan all column headers and determine their heights. Cache the values
* since vertical mode repeats the headers for every record.
*/
- header_height = (int *) pg_malloc(cont->ncolumns * sizeof(int));
+ header_height = pg_malloc_array(int, cont->ncolumns);
for (i = 0; i < cont->ncolumns; i++)
{
pg_wcssize((const unsigned char *) cont->headers[i],
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 5d74714ffc6..e78952d448d 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -1002,7 +1002,7 @@ psql_scan_create(const PsqlScanCallbacks *callbacks)
{
PsqlScanState state;
- state = (PsqlScanStateData *) pg_malloc0(sizeof(PsqlScanStateData));
+ state = pg_malloc0_object(PsqlScanStateData);
state->callbacks = callbacks;
@@ -1376,7 +1376,7 @@ psqlscan_push_new_buffer(PsqlScanState state, const char *newstr,
{
StackElem *stackelem;
- stackelem = (StackElem *) pg_malloc(sizeof(StackElem));
+ stackelem = pg_malloc_object(StackElem);
/*
* In current usage, the passed varname points at the current flex input
@@ -1479,7 +1479,7 @@ psqlscan_prepare_buffer(PsqlScanState state, const char *txt, int len,
char *newtxt;
/* Flex wants two \0 characters after the actual data */
- newtxt = pg_malloc(len + 2);
+ newtxt = pg_malloc_array(char, (len + 2));
*txtcopy = newtxt;
newtxt[len] = newtxt[len + 1] = YY_END_OF_BUFFER_CHAR;
@@ -1548,7 +1548,7 @@ psqlscan_emit(PsqlScanState state, const char *txt, int len)
char *
psqlscan_extract_substring(PsqlScanState state, const char *txt, int len)
{
- char *result = (char *) pg_malloc(len + 1);
+ char *result = pg_malloc_array(char, (len + 1));
if (state->safe_encoding)
memcpy(result, txt, len);
diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c
index ec698fc6728..03c11bae7c8 100644
--- a/src/fe_utils/simple_list.c
+++ b/src/fe_utils/simple_list.c
@@ -27,7 +27,7 @@ simple_oid_list_append(SimpleOidList *list, Oid val)
{
SimpleOidListCell *cell;
- cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+ cell = pg_malloc_object(SimpleOidListCell);
cell->next = NULL;
cell->val = val;
@@ -163,7 +163,7 @@ simple_ptr_list_append(SimplePtrList *list, void *ptr)
{
SimplePtrListCell *cell;
- cell = (SimplePtrListCell *) pg_malloc(sizeof(SimplePtrListCell));
+ cell = pg_malloc_object(SimplePtrListCell);
cell->next = NULL;
cell->ptr = ptr;
--
2.53.0
Attachments:
[text/plain] v1-0001-fe_utils-Use-pg_malloc_object-and-pg_malloc_array.patch (8.5K, ../../[email protected]/2-v1-0001-fe_utils-Use-pg_malloc_object-and-pg_malloc_array.patch)
download | inline diff:
From 6ad0e5be35029a1aa32452cfeba5fe0ec55b1f5d Mon Sep 17 00:00:00 2001
From: Henrik TJ <[email protected]>
Date: Fri, 13 Feb 2026 15:51:47 +0100
Subject: [PATCH] fe_utils: Use pg_malloc_object() and pg_malloc_array()
Use more high-level allocation routines in src/fe_utils.
Similar to 31d3847a37be and 6736dea14af
---
src/fe_utils/conditional.c | 4 ++--
src/fe_utils/print.c | 48 +++++++++++++++++++-------------------
src/fe_utils/psqlscan.l | 8 +++----
src/fe_utils/simple_list.c | 4 ++--
4 files changed, 32 insertions(+), 32 deletions(-)
diff --git a/src/fe_utils/conditional.c b/src/fe_utils/conditional.c
index deba61e0d81..537c76ed3cd 100644
--- a/src/fe_utils/conditional.c
+++ b/src/fe_utils/conditional.c
@@ -17,7 +17,7 @@
ConditionalStack
conditional_stack_create(void)
{
- ConditionalStack cstack = pg_malloc(sizeof(ConditionalStackData));
+ ConditionalStack cstack = pg_malloc_object(ConditionalStackData);
cstack->head = NULL;
return cstack;
@@ -52,7 +52,7 @@ conditional_stack_destroy(ConditionalStack cstack)
void
conditional_stack_push(ConditionalStack cstack, ifState new_state)
{
- IfStackElem *p = (IfStackElem *) pg_malloc(sizeof(IfStackElem));
+ IfStackElem *p = pg_malloc_object(IfStackElem);
p->if_state = new_state;
p->query_len = -1;
diff --git a/src/fe_utils/print.c b/src/fe_utils/print.c
index ef52cdee9b7..12d969e8666 100644
--- a/src/fe_utils/print.c
+++ b/src/fe_utils/print.c
@@ -344,7 +344,7 @@ format_numeric_locale(const char *my_str)
return pg_strdup(my_str);
new_len = strlen(my_str) + additional_numeric_locale_len(my_str);
- new_str = pg_malloc(new_len + 1);
+ new_str = pg_malloc_array(char, (new_len + 1));
new_str_pos = 0;
int_len = integer_digits(my_str);
@@ -692,18 +692,18 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
if (cont->ncolumns > 0)
{
col_count = cont->ncolumns;
- width_header = pg_malloc0(col_count * sizeof(*width_header));
- width_average = pg_malloc0(col_count * sizeof(*width_average));
- max_width = pg_malloc0(col_count * sizeof(*max_width));
- width_wrap = pg_malloc0(col_count * sizeof(*width_wrap));
- max_nl_lines = pg_malloc0(col_count * sizeof(*max_nl_lines));
- curr_nl_line = pg_malloc0(col_count * sizeof(*curr_nl_line));
- col_lineptrs = pg_malloc0(col_count * sizeof(*col_lineptrs));
- max_bytes = pg_malloc0(col_count * sizeof(*max_bytes));
- format_buf = pg_malloc0(col_count * sizeof(*format_buf));
- header_done = pg_malloc0(col_count * sizeof(*header_done));
- bytes_output = pg_malloc0(col_count * sizeof(*bytes_output));
- wrap = pg_malloc0(col_count * sizeof(*wrap));
+ width_header = pg_malloc0_array(unsigned int, col_count);
+ width_average = pg_malloc0_array(unsigned int, col_count);
+ max_width = pg_malloc0_array(unsigned int, col_count);
+ width_wrap = pg_malloc0_array(unsigned int, col_count);
+ max_nl_lines = pg_malloc0_array(unsigned int, col_count);
+ curr_nl_line = pg_malloc0_array(unsigned int, col_count);
+ col_lineptrs = pg_malloc0_array(struct lineptr *, col_count);
+ max_bytes = pg_malloc0_array(unsigned int, col_count);
+ format_buf = pg_malloc0_array(unsigned char *, col_count);
+ header_done = pg_malloc0_array(bool, col_count);
+ bytes_output = pg_malloc0_array(int, col_count);
+ wrap = pg_malloc0_array(printTextLineWrap, col_count);
}
else
{
@@ -798,10 +798,10 @@ print_aligned_text(const printTableContent *cont, FILE *fout, bool is_pager)
for (i = 0; i < col_count; i++)
{
/* Add entry for ptr == NULL array termination */
- col_lineptrs[i] = pg_malloc0((max_nl_lines[i] + 1) *
- sizeof(**col_lineptrs));
+ col_lineptrs[i] = pg_malloc0_array(struct lineptr,
+ (max_nl_lines[i] + 1));
- format_buf[i] = pg_malloc(max_bytes[i] + 1);
+ format_buf[i] = pg_malloc_array(unsigned char, (max_bytes[i] + 1));
col_lineptrs[i]->ptr = format_buf[i];
}
@@ -1409,8 +1409,8 @@ print_aligned_vertical(const printTableContent *cont,
* We now have all the information we need to setup the formatting
* structures
*/
- dlineptr = pg_malloc((sizeof(*dlineptr)) * (dheight + 1));
- hlineptr = pg_malloc((sizeof(*hlineptr)) * (hheight + 1));
+ dlineptr = pg_malloc_array(struct lineptr, (dheight + 1));
+ hlineptr = pg_malloc_array(struct lineptr, (hheight + 1));
dlineptr->ptr = pg_malloc(dformatsize);
hlineptr->ptr = pg_malloc(hformatsize);
@@ -3198,7 +3198,7 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
content->ncolumns = ncolumns;
content->nrows = nrows;
- content->headers = pg_malloc0((ncolumns + 1) * sizeof(*content->headers));
+ content->headers = pg_malloc0_array(const char *, (ncolumns + 1));
total_cells = (uint64) ncolumns * nrows;
/* Catch possible overflow. Using >= here allows adding 1 below */
@@ -3209,12 +3209,12 @@ printTableInit(printTableContent *const content, const printTableOpt *opt,
SIZE_MAX / sizeof(*content->cells));
exit(EXIT_FAILURE);
}
- content->cells = pg_malloc0((total_cells + 1) * sizeof(*content->cells));
+ content->cells = pg_malloc0_array(const char *, (total_cells + 1));
content->cellmustfree = NULL;
content->footers = NULL;
- content->aligns = pg_malloc0((ncolumns + 1) * sizeof(*content->align));
+ content->aligns = pg_malloc0_array(char, (ncolumns + 1));
content->header = content->headers;
content->cell = content->cells;
@@ -3305,7 +3305,7 @@ printTableAddCell(printTableContent *const content, char *cell,
{
if (content->cellmustfree == NULL)
content->cellmustfree =
- pg_malloc0((total_cells + 1) * sizeof(bool));
+ pg_malloc0_array(bool, (total_cells + 1));
content->cellmustfree[content->cellsadded] = true;
}
@@ -3330,7 +3330,7 @@ printTableAddFooter(printTableContent *const content, const char *footer)
{
printTableFooter *f;
- f = pg_malloc0(sizeof(*f));
+ f = pg_malloc0_object(printTableFooter);
f->data = pg_strdup(footer);
if (content->footers == NULL)
@@ -3477,7 +3477,7 @@ count_table_lines(const printTableContent *cont,
* Scan all column headers and determine their heights. Cache the values
* since vertical mode repeats the headers for every record.
*/
- header_height = (int *) pg_malloc(cont->ncolumns * sizeof(int));
+ header_height = pg_malloc_array(int, cont->ncolumns);
for (i = 0; i < cont->ncolumns; i++)
{
pg_wcssize((const unsigned char *) cont->headers[i],
diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l
index 5d74714ffc6..e78952d448d 100644
--- a/src/fe_utils/psqlscan.l
+++ b/src/fe_utils/psqlscan.l
@@ -1002,7 +1002,7 @@ psql_scan_create(const PsqlScanCallbacks *callbacks)
{
PsqlScanState state;
- state = (PsqlScanStateData *) pg_malloc0(sizeof(PsqlScanStateData));
+ state = pg_malloc0_object(PsqlScanStateData);
state->callbacks = callbacks;
@@ -1376,7 +1376,7 @@ psqlscan_push_new_buffer(PsqlScanState state, const char *newstr,
{
StackElem *stackelem;
- stackelem = (StackElem *) pg_malloc(sizeof(StackElem));
+ stackelem = pg_malloc_object(StackElem);
/*
* In current usage, the passed varname points at the current flex input
@@ -1479,7 +1479,7 @@ psqlscan_prepare_buffer(PsqlScanState state, const char *txt, int len,
char *newtxt;
/* Flex wants two \0 characters after the actual data */
- newtxt = pg_malloc(len + 2);
+ newtxt = pg_malloc_array(char, (len + 2));
*txtcopy = newtxt;
newtxt[len] = newtxt[len + 1] = YY_END_OF_BUFFER_CHAR;
@@ -1548,7 +1548,7 @@ psqlscan_emit(PsqlScanState state, const char *txt, int len)
char *
psqlscan_extract_substring(PsqlScanState state, const char *txt, int len)
{
- char *result = (char *) pg_malloc(len + 1);
+ char *result = pg_malloc_array(char, (len + 1));
if (state->safe_encoding)
memcpy(result, txt, len);
diff --git a/src/fe_utils/simple_list.c b/src/fe_utils/simple_list.c
index ec698fc6728..03c11bae7c8 100644
--- a/src/fe_utils/simple_list.c
+++ b/src/fe_utils/simple_list.c
@@ -27,7 +27,7 @@ simple_oid_list_append(SimpleOidList *list, Oid val)
{
SimpleOidListCell *cell;
- cell = (SimpleOidListCell *) pg_malloc(sizeof(SimpleOidListCell));
+ cell = pg_malloc_object(SimpleOidListCell);
cell->next = NULL;
cell->val = val;
@@ -163,7 +163,7 @@ simple_ptr_list_append(SimplePtrList *list, void *ptr)
{
SimplePtrListCell *cell;
- cell = (SimplePtrListCell *) pg_malloc(sizeof(SimplePtrListCell));
+ cell = pg_malloc_object(SimplePtrListCell);
cell->next = NULL;
cell->ptr = ptr;
--
2.53.0
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: Use pg_malloc macros in src/fe_utils
@ 2026-02-23 02:17 Andreas Karlsson <[email protected]>
parent: Henrik TJ <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Andreas Karlsson @ 2026-02-23 02:17 UTC (permalink / raw)
To: Henrik TJ <[email protected]>; pgsql-hackers
On 2/18/26 4:05 PM, Henrik TJ wrote:
> Inspired by [1], I took a stab at converting src/fe_utils to the new
> pg_malloc macros.
Thanks for the patch!
Looks like a nice change but why not just fix all instances of it in one
swoop? It cannot be that many as there are 166 calls to pg_malloc() and
62 calls to pg_malloc0() after your patch that need to be looked at.
--
Andreas Karlsson
Percona
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: Use pg_malloc macros in src/fe_utils
@ 2026-02-24 03:36 Michael Paquier <[email protected]>
parent: Andreas Karlsson <[email protected]>
0 siblings, 1 reply; 5+ messages in thread
From: Michael Paquier @ 2026-02-24 03:36 UTC (permalink / raw)
To: Andreas Karlsson <[email protected]>; +Cc: Henrik TJ <[email protected]>; pgsql-hackers
On Mon, Feb 23, 2026 at 03:17:52AM +0100, Andreas Karlsson wrote:
> Looks like a nice change but why not just fix all instances of it in one
> swoop? It cannot be that many as there are 166 calls to pg_malloc() and 62
> calls to pg_malloc0() after your patch that need to be looked at.
FWIW, I don't really mind if these changes are proposed gradually, and
this looked fine enough on its own. So applied.
--
Michael
Attachments:
[application/pgp-signature] signature.asc (833B, ../../[email protected]/2-signature.asc)
download
^ permalink raw reply [nested|flat] 5+ messages in thread
* Re: Use pg_malloc macros in src/fe_utils
@ 2026-02-27 01:15 Andreas Karlsson <[email protected]>
parent: Michael Paquier <[email protected]>
0 siblings, 0 replies; 5+ messages in thread
From: Andreas Karlsson @ 2026-02-27 01:15 UTC (permalink / raw)
To: Michael Paquier <[email protected]>; +Cc: Henrik TJ <[email protected]>; pgsql-hackers
On 2/24/26 4:36 AM, Michael Paquier wrote:
> On Mon, Feb 23, 2026 at 03:17:52AM +0100, Andreas Karlsson wrote:
>> Looks like a nice change but why not just fix all instances of it in one
>> swoop? It cannot be that many as there are 166 calls to pg_malloc() and 62
>> calls to pg_malloc0() after your patch that need to be looked at.
>
> FWIW, I don't really mind if these changes are proposed gradually, and
> this looked fine enough on its own. So applied.
Fair, here is a patch which should handle all uses in the frontend code
so we follow this pattern consistently to encourage new code to use
these macros.
When doing this I found two things which I am ot sure what the cleanest
way to handle would be so I broke them out into separate patches.
1. What should we do about when we allocate a an array of characters?
Would it make sense to use pg_array_alloc() or would that jsut be silly?
For example:
-pad = (char *) pg_malloc(l + 1);
+pad = pg_malloc_array(char, l + 1);
2. I found a small and harmless thinko. The buffer in verify_tar_file()
is actually a char * but for some reason the code did the following:
buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));
What should we do about it? Just skip the "sizof(uint8)"?
Andreas
Attachments:
[text/x-patch] v1-0001-Use-pg_malloc_object-and-pg_alloc_array-variants-.patch (50.7K, ../../[email protected]/2-v1-0001-Use-pg_malloc_object-and-pg_alloc_array-variants-.patch)
download | inline diff:
From 0c62229ff9a8f1a5175393b9c1d51bb379ac31ea Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email protected]>
Date: Fri, 27 Feb 2026 02:03:46 +0100
Subject: [PATCH v1 1/3] Use pg_malloc_object() and pg_alloc_array() variants
in frontend code
Where possible use the pg_*_object() and pg_*_array() macros in our frontend
code to encourage newly added code to use the macros.
---
contrib/oid2name/oid2name.c | 16 +++---
src/bin/initdb/initdb.c | 6 +--
src/bin/pg_amcheck/pg_amcheck.c | 8 +--
src/bin/pg_basebackup/pg_basebackup.c | 4 +-
src/bin/pg_basebackup/pg_recvlogical.c | 2 +-
src/bin/pg_basebackup/streamutil.c | 8 +--
src/bin/pg_basebackup/walmethods.c | 12 ++---
src/bin/pg_combinebackup/load_manifest.c | 4 +-
src/bin/pg_combinebackup/pg_combinebackup.c | 6 +--
src/bin/pg_combinebackup/reconstruct.c | 10 ++--
src/bin/pg_combinebackup/write_manifest.c | 2 +-
src/bin/pg_ctl/pg_ctl.c | 4 +-
src/bin/pg_rewind/datapagemap.c | 2 +-
src/bin/pg_rewind/libpq_source.c | 2 +-
src/bin/pg_rewind/local_source.c | 2 +-
src/bin/pg_rewind/pg_rewind.c | 2 +-
src/bin/pg_rewind/timeline.c | 6 +--
src/bin/pg_upgrade/check.c | 4 +-
src/bin/pg_upgrade/function.c | 4 +-
src/bin/pg_upgrade/info.c | 11 ++--
src/bin/pg_upgrade/parallel.c | 12 ++---
src/bin/pg_upgrade/slru_io.c | 2 +-
src/bin/pg_upgrade/tablespace.c | 4 +-
src/bin/pg_upgrade/task.c | 8 +--
src/bin/pg_verifybackup/astreamer_verify.c | 2 +-
src/bin/pg_verifybackup/pg_verifybackup.c | 6 +--
src/bin/pgbench/exprparse.y | 16 +++---
src/bin/pgbench/pgbench.c | 22 ++++----
src/bin/psql/command.c | 6 +--
src/bin/psql/copy.c | 2 +-
src/bin/psql/crosstabview.c | 15 +++---
src/bin/psql/describe.c | 4 +-
src/bin/psql/tab-complete.in.c | 7 ++-
src/bin/psql/variables.c | 6 +--
src/bin/scripts/reindexdb.c | 6 +--
src/test/isolation/isolationtester.c | 12 ++---
src/test/isolation/specparse.y | 50 +++++++++----------
.../modules/libpq_pipeline/libpq_pipeline.c | 8 +--
src/test/regress/pg_regress.c | 6 +--
39 files changed, 152 insertions(+), 157 deletions(-)
diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index 63e6ce2dae8..1e9efcd3953 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -237,13 +237,13 @@ add_one_elt(char *eltname, eary *eary)
if (eary->alloc == 0)
{
eary ->alloc = 8;
- eary ->array = (char **) pg_malloc(8 * sizeof(char *));
+ eary ->array = pg_malloc_array(char *, 8);
}
else if (eary->num >= eary->alloc)
{
eary ->alloc *= 2;
- eary ->array = (char **) pg_realloc(eary->array,
- eary->alloc * sizeof(char *));
+ eary ->array = pg_realloc_array(eary->array, char *,
+ eary->alloc);
}
eary ->array[eary->num] = pg_strdup(eltname);
@@ -400,7 +400,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
nfields = PQnfields(res);
/* for each field, get the needed width */
- length = (int *) pg_malloc(sizeof(int) * nfields);
+ length = pg_malloc_array(int, nfields);
for (j = 0; j < nfields; j++)
length[j] = strlen(PQfname(res, j));
@@ -585,11 +585,11 @@ main(int argc, char **argv)
struct options *my_opts;
PGconn *pgconn;
- my_opts = (struct options *) pg_malloc(sizeof(struct options));
+ my_opts = pg_malloc_object(struct options);
- my_opts->oids = (eary *) pg_malloc(sizeof(eary));
- my_opts->tables = (eary *) pg_malloc(sizeof(eary));
- my_opts->filenumbers = (eary *) pg_malloc(sizeof(eary));
+ my_opts->oids = pg_malloc_object(eary);
+ my_opts->tables = pg_malloc_object(eary);
+ my_opts->filenumbers = pg_malloc_object(eary);
my_opts->oids->num = my_opts->oids->alloc = 0;
my_opts->tables->num = my_opts->tables->alloc = 0;
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 7c49dd433a7..53ec1544ff3 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -444,7 +444,7 @@ escape_quotes_bki(const char *src)
static void
add_stringlist_item(_stringlist **listhead, const char *str)
{
- _stringlist *newentry = pg_malloc(sizeof(_stringlist));
+ _stringlist *newentry = pg_malloc_object(_stringlist);
_stringlist *oldentry;
newentry->str = pg_strdup(str);
@@ -687,7 +687,7 @@ readfile(const char *path)
initStringInfo(&line);
maxlines = 1024;
- result = (char **) pg_malloc(maxlines * sizeof(char *));
+ result = pg_malloc_array(char *, maxlines);
n = 0;
while (pg_get_line_buf(infile, &line))
@@ -696,7 +696,7 @@ readfile(const char *path)
if (n >= maxlines - 1)
{
maxlines *= 2;
- result = (char **) pg_realloc(result, maxlines * sizeof(char *));
+ result = pg_realloc_array(result, char *, maxlines);
}
result[n++] = pg_strdup(line.data);
diff --git a/src/bin/pg_amcheck/pg_amcheck.c b/src/bin/pg_amcheck/pg_amcheck.c
index 03e24a2577c..09ba0596400 100644
--- a/src/bin/pg_amcheck/pg_amcheck.c
+++ b/src/bin/pg_amcheck/pg_amcheck.c
@@ -1338,7 +1338,7 @@ extend_pattern_info_array(PatternInfoArray *pia)
PatternInfo *result;
pia->len++;
- pia->data = (PatternInfo *) pg_realloc(pia->data, pia->len * sizeof(PatternInfo));
+ pia->data = pg_realloc_array(pia->data, PatternInfo, pia->len);
result = &pia->data[pia->len - 1];
memset(result, 0, sizeof(*result));
@@ -1593,7 +1593,7 @@ compile_database_list(PGconn *conn, SimplePtrList *databases,
if (initial_dbname)
{
- DatabaseInfo *dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo));
+ DatabaseInfo *dat = pg_malloc0_object(DatabaseInfo);
/* This database is included. Add to list */
if (opts.verbose)
@@ -1738,7 +1738,7 @@ compile_database_list(PGconn *conn, SimplePtrList *databases,
if (opts.verbose)
pg_log_info("including database \"%s\"", datname);
- dat = (DatabaseInfo *) pg_malloc0(sizeof(DatabaseInfo));
+ dat = pg_malloc0_object(DatabaseInfo);
dat->datname = pstrdup(datname);
simple_ptr_list_append(databases, dat);
}
@@ -2202,7 +2202,7 @@ compile_relation_list_one_db(PGconn *conn, SimplePtrList *relations,
{
/* Current record pertains to a relation */
- RelationInfo *rel = (RelationInfo *) pg_malloc0(sizeof(RelationInfo));
+ RelationInfo *rel = pg_malloc0_object(RelationInfo);
Assert(OidIsValid(oid));
Assert((is_heap && !is_btree) || (is_btree && !is_heap));
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 1e3a8203f77..fa169a8d642 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -320,7 +320,7 @@ kill_bgchild_atexit(void)
static void
tablespace_list_append(const char *arg)
{
- TablespaceListCell *cell = (TablespaceListCell *) pg_malloc0(sizeof(TablespaceListCell));
+ TablespaceListCell *cell = pg_malloc0_object(TablespaceListCell);
char *dst;
char *dst_ptr;
const char *arg_ptr;
@@ -623,7 +623,7 @@ StartLogStreamer(char *startpos, uint32 timeline, char *sysidentifier,
lo;
char statusdir[MAXPGPATH];
- param = pg_malloc0(sizeof(logstreamer_param));
+ param = pg_malloc0_object(logstreamer_param);
param->timeline = timeline;
param->sysidentifier = sysidentifier;
param->wal_compress_algorithm = wal_compress_algorithm;
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index abc6cd85a6d..be71783b370 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -820,7 +820,7 @@ main(int argc, char **argv)
}
noptions += 1;
- options = pg_realloc(options, sizeof(char *) * noptions * 2);
+ options = pg_realloc_array(options, char *, noptions * 2);
options[(noptions - 1) * 2] = data;
options[(noptions - 1) * 2 + 1] = val;
diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c
index 1d404e778a0..76abdfa2ae6 100644
--- a/src/bin/pg_basebackup/streamutil.c
+++ b/src/bin/pg_basebackup/streamutil.c
@@ -94,8 +94,8 @@ GetConnection(void)
argcount++;
}
- keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
- values = pg_malloc0((argcount + 1) * sizeof(*values));
+ keywords = pg_malloc0_array(const char *, argcount + 1);
+ values = pg_malloc0_array(const char *, argcount + 1);
/*
* Set dbname here already, so it can be overridden by a dbname in the
@@ -117,8 +117,8 @@ GetConnection(void)
}
else
{
- keywords = pg_malloc0((argcount + 1) * sizeof(*keywords));
- values = pg_malloc0((argcount + 1) * sizeof(*values));
+ keywords = pg_malloc0_array(const char *, argcount + 1);
+ values = pg_malloc0_array(const char *, argcount + 1);
keywords[i] = "dbname";
values[i] = (dbname == NULL) ? "replication" : dbname;
i++;
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 17d22c79f68..476673cf729 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -275,7 +275,7 @@ dir_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
}
}
- f = pg_malloc0(sizeof(DirectoryMethodFile));
+ f = pg_malloc0_object(DirectoryMethodFile);
#ifdef HAVE_LIBZ
if (wwmethod->compression_algorithm == PG_COMPRESSION_GZIP)
f->gzfp = gzfp;
@@ -643,7 +643,7 @@ CreateWalDirectoryMethod(const char *basedir,
{
DirectoryMethodData *wwmethod;
- wwmethod = pg_malloc0(sizeof(DirectoryMethodData));
+ wwmethod = pg_malloc0_object(DirectoryMethodData);
*((const WalWriteMethodOps **) &wwmethod->base.ops) =
&WalDirectoryMethodOps;
wwmethod->base.compression_algorithm = compression_algorithm;
@@ -825,7 +825,7 @@ static char *
tar_get_file_name(WalWriteMethod *wwmethod, const char *pathname,
const char *temp_suffix)
{
- char *filename = pg_malloc0(MAXPGPATH * sizeof(char));
+ char *filename = pg_malloc0_array(char, MAXPGPATH);
snprintf(filename, MAXPGPATH, "%s%s",
pathname, temp_suffix ? temp_suffix : "");
@@ -859,7 +859,7 @@ tar_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
#ifdef HAVE_LIBZ
if (wwmethod->compression_algorithm == PG_COMPRESSION_GZIP)
{
- tar_data->zp = (z_streamp) pg_malloc(sizeof(z_stream));
+ tar_data->zp = pg_malloc_object(z_stream);
tar_data->zp->zalloc = Z_NULL;
tar_data->zp->zfree = Z_NULL;
tar_data->zp->opaque = Z_NULL;
@@ -893,7 +893,7 @@ tar_open_for_write(WalWriteMethod *wwmethod, const char *pathname,
return NULL;
}
- tar_data->currentfile = pg_malloc0(sizeof(TarMethodFile));
+ tar_data->currentfile = pg_malloc0_object(TarMethodFile);
tar_data->currentfile->base.wwmethod = wwmethod;
tmppath = tar_get_file_name(wwmethod, pathname, temp_suffix);
@@ -1360,7 +1360,7 @@ CreateWalTarMethod(const char *tarbase,
const char *suffix = (compression_algorithm == PG_COMPRESSION_GZIP) ?
".tar.gz" : ".tar";
- wwmethod = pg_malloc0(sizeof(TarMethodData));
+ wwmethod = pg_malloc0_object(TarMethodData);
*((const WalWriteMethodOps **) &wwmethod->base.ops) =
&WalTarMethodOps;
wwmethod->base.compression_algorithm = compression_algorithm;
diff --git a/src/bin/pg_combinebackup/load_manifest.c b/src/bin/pg_combinebackup/load_manifest.c
index c363ac6187e..2e50b7af4d2 100644
--- a/src/bin/pg_combinebackup/load_manifest.c
+++ b/src/bin/pg_combinebackup/load_manifest.c
@@ -85,7 +85,7 @@ load_backup_manifests(int n_backups, char **backup_directories)
manifest_data **result;
int i;
- result = pg_malloc(sizeof(manifest_data *) * n_backups);
+ result = pg_malloc_array(manifest_data *, n_backups);
for (i = 0; i < n_backups; ++i)
result[i] = load_backup_manifest(backup_directories[i]);
@@ -139,7 +139,7 @@ load_backup_manifest(char *backup_directory)
/* Create the hash table. */
ht = manifest_files_create(initial_size, NULL);
- result = pg_malloc0(sizeof(manifest_data));
+ result = pg_malloc0_object(manifest_data);
result->files = ht;
context.private_data = result;
context.version_cb = combinebackup_version_cb;
diff --git a/src/bin/pg_combinebackup/pg_combinebackup.c b/src/bin/pg_combinebackup/pg_combinebackup.c
index b9f26ce782e..ac7eb0940d5 100644
--- a/src/bin/pg_combinebackup/pg_combinebackup.c
+++ b/src/bin/pg_combinebackup/pg_combinebackup.c
@@ -455,7 +455,7 @@ main(int argc, char *argv[])
static void
add_tablespace_mapping(cb_options *opt, char *arg)
{
- cb_tablespace_mapping *tsmap = pg_malloc0(sizeof(cb_tablespace_mapping));
+ cb_tablespace_mapping *tsmap = pg_malloc0_object(cb_tablespace_mapping);
char *dst;
char *dst_ptr;
char *arg_ptr;
@@ -1171,7 +1171,7 @@ process_directory_recursively(Oid tsoid,
static void
remember_to_cleanup_directory(char *target_path, bool rmtopdir)
{
- cb_cleanup_dir *dir = pg_malloc(sizeof(cb_cleanup_dir));
+ cb_cleanup_dir *dir = pg_malloc_object(cb_cleanup_dir);
dir->target_path = target_path;
dir->rmtopdir = rmtopdir;
@@ -1259,7 +1259,7 @@ scan_for_existing_tablespaces(char *pathname, cb_options *opt)
}
/* Create a new tablespace object. */
- ts = pg_malloc0(sizeof(cb_tablespace));
+ ts = pg_malloc0_object(cb_tablespace);
ts->oid = oid;
/*
diff --git a/src/bin/pg_combinebackup/reconstruct.c b/src/bin/pg_combinebackup/reconstruct.c
index da60f7d0297..3349aa2441d 100644
--- a/src/bin/pg_combinebackup/reconstruct.c
+++ b/src/bin/pg_combinebackup/reconstruct.c
@@ -120,7 +120,7 @@ reconstruct_from_incremental_file(char *input_filename,
* Every block must come either from the latest version of the file or
* from one of the prior backups.
*/
- source = pg_malloc0(sizeof(rfile *) * (1 + n_prior_backups));
+ source = pg_malloc0_array(rfile *, 1 + n_prior_backups);
/*
* Use the information from the latest incremental file to figure out how
@@ -135,8 +135,8 @@ reconstruct_from_incremental_file(char *input_filename,
* need to obtain it and at what offset in that file it's stored.
* sourcemap gives us the first of these things, and offsetmap the latter.
*/
- sourcemap = pg_malloc0(sizeof(rfile *) * block_length);
- offsetmap = pg_malloc0(sizeof(off_t) * block_length);
+ sourcemap = pg_malloc0_array(rfile *, block_length);
+ offsetmap = pg_malloc0_array(off_t, block_length);
/*
* Every block that is present in the newest incremental file should be
@@ -483,7 +483,7 @@ make_incremental_rfile(char *filename)
if (rf->num_blocks > 0)
{
rf->relative_block_numbers =
- pg_malloc0(sizeof(BlockNumber) * rf->num_blocks);
+ pg_malloc0_array(BlockNumber, rf->num_blocks);
read_bytes(rf, rf->relative_block_numbers,
sizeof(BlockNumber) * rf->num_blocks);
}
@@ -512,7 +512,7 @@ make_rfile(char *filename, bool missing_ok)
{
rfile *rf;
- rf = pg_malloc0(sizeof(rfile));
+ rf = pg_malloc0_object(rfile);
rf->filename = pstrdup(filename);
if ((rf->fd = open(filename, O_RDONLY | PG_BINARY, 0)) < 0)
{
diff --git a/src/bin/pg_combinebackup/write_manifest.c b/src/bin/pg_combinebackup/write_manifest.c
index 4f3ed2c173c..715286043b5 100644
--- a/src/bin/pg_combinebackup/write_manifest.c
+++ b/src/bin/pg_combinebackup/write_manifest.c
@@ -47,7 +47,7 @@ static size_t hex_encode(const uint8 *src, size_t len, char *dst);
manifest_writer *
create_manifest_writer(char *directory, uint64 system_identifier)
{
- manifest_writer *mwriter = pg_malloc(sizeof(manifest_writer));
+ manifest_writer *mwriter = pg_malloc_object(manifest_writer);
snprintf(mwriter->pathname, MAXPGPATH, "%s/backup_manifest", directory);
mwriter->fd = -1;
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 122856b599e..3cc61455dcb 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -346,7 +346,7 @@ readfile(const char *path, int *numlines)
{
/* empty file */
close(fd);
- result = (char **) pg_malloc(sizeof(char *));
+ result = pg_malloc_object(char *);
*result = NULL;
return result;
}
@@ -374,7 +374,7 @@ readfile(const char *path, int *numlines)
}
/* set up the result buffer */
- result = (char **) pg_malloc((nlines + 1) * sizeof(char *));
+ result = pg_malloc_array(char *, nlines + 1);
*numlines = nlines;
/* now split the buffer into lines */
diff --git a/src/bin/pg_rewind/datapagemap.c b/src/bin/pg_rewind/datapagemap.c
index 94bac43fb92..8e8cdda5005 100644
--- a/src/bin/pg_rewind/datapagemap.c
+++ b/src/bin/pg_rewind/datapagemap.c
@@ -76,7 +76,7 @@ datapagemap_iterate(datapagemap_t *map)
{
datapagemap_iterator_t *iter;
- iter = pg_malloc(sizeof(datapagemap_iterator_t));
+ iter = pg_malloc0_object(datapagemap_iterator_t);
iter->map = map;
iter->nextblkno = 0;
diff --git a/src/bin/pg_rewind/libpq_source.c b/src/bin/pg_rewind/libpq_source.c
index 15a05d9a8d0..6955bc575ea 100644
--- a/src/bin/pg_rewind/libpq_source.c
+++ b/src/bin/pg_rewind/libpq_source.c
@@ -84,7 +84,7 @@ init_libpq_source(PGconn *conn)
init_libpq_conn(conn);
- src = pg_malloc0(sizeof(libpq_source));
+ src = pg_malloc0_object(libpq_source);
src->common.traverse_files = libpq_traverse_files;
src->common.fetch_file = libpq_fetch_file;
diff --git a/src/bin/pg_rewind/local_source.c b/src/bin/pg_rewind/local_source.c
index 97d6f65009b..4841cf01fb7 100644
--- a/src/bin/pg_rewind/local_source.c
+++ b/src/bin/pg_rewind/local_source.c
@@ -39,7 +39,7 @@ init_local_source(const char *datadir)
{
local_source *src;
- src = pg_malloc0(sizeof(local_source));
+ src = pg_malloc0_object(local_source);
src->common.traverse_files = local_traverse_files;
src->common.fetch_file = local_fetch_file;
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index d0aafd7e7a6..9d745d4b25b 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -874,7 +874,7 @@ getTimelineHistory(TimeLineID tli, bool is_source, int *nentries)
*/
if (tli == 1)
{
- history = (TimeLineHistoryEntry *) pg_malloc(sizeof(TimeLineHistoryEntry));
+ history = pg_malloc_object(TimeLineHistoryEntry);
history->tli = tli;
history->begin = history->end = InvalidXLogRecPtr;
*nentries = 1;
diff --git a/src/bin/pg_rewind/timeline.c b/src/bin/pg_rewind/timeline.c
index 69f589f67c9..dda06eaa0bc 100644
--- a/src/bin/pg_rewind/timeline.c
+++ b/src/bin/pg_rewind/timeline.c
@@ -91,7 +91,7 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
lasttli = tli;
nlines++;
- entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+ entries = pg_realloc_array(entries, TimeLineHistoryEntry, nlines);
entry = &entries[nlines - 1];
entry->tli = tli;
@@ -115,9 +115,9 @@ rewind_parseTimeLineHistory(char *buffer, TimeLineID targetTLI, int *nentries)
*/
nlines++;
if (entries)
- entries = pg_realloc(entries, nlines * sizeof(TimeLineHistoryEntry));
+ entries = pg_realloc_array(entries, TimeLineHistoryEntry, nlines);
else
- entries = pg_malloc(1 * sizeof(TimeLineHistoryEntry));
+ entries = pg_malloc_array(TimeLineHistoryEntry, 1);
entry = &entries[nlines - 1];
entry->tli = targetTLI;
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 5afa65db98e..eb35c68d450 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -482,8 +482,8 @@ check_for_data_types_usage(ClusterInfo *cluster)
}
/* Allocate memory for queries and for task states */
- queries = pg_malloc0(sizeof(char *) * n_data_types_usage_checks);
- states = pg_malloc0(sizeof(struct data_type_check_state) * n_data_types_usage_checks);
+ queries = pg_malloc0_array(char *, n_data_types_usage_checks);
+ states = pg_malloc0_array(struct data_type_check_state, n_data_types_usage_checks);
for (int i = 0; i < n_data_types_usage_checks; i++)
{
diff --git a/src/bin/pg_upgrade/function.c b/src/bin/pg_upgrade/function.c
index 850c9238c11..a3184f95665 100644
--- a/src/bin/pg_upgrade/function.c
+++ b/src/bin/pg_upgrade/function.c
@@ -83,7 +83,7 @@ get_loadable_libraries(void)
struct loadable_libraries_state state;
char *query;
- state.ress = (PGresult **) pg_malloc(old_cluster.dbarr.ndbs * sizeof(PGresult *));
+ state.ress = pg_malloc_array(PGresult *, old_cluster.dbarr.ndbs);
state.totaltups = 0;
query = psprintf("SELECT DISTINCT probin "
@@ -105,7 +105,7 @@ get_loadable_libraries(void)
* plugins.
*/
n_libinfos = state.totaltups + count_old_cluster_logical_slots();
- os_info.libraries = (LibraryInfo *) pg_malloc(sizeof(LibraryInfo) * n_libinfos);
+ os_info.libraries = pg_malloc_array(LibraryInfo, n_libinfos);
totaltups = 0;
for (dbnum = 0; dbnum < old_cluster.dbarr.ndbs; dbnum++)
diff --git a/src/bin/pg_upgrade/info.c b/src/bin/pg_upgrade/info.c
index ad4b1530e6d..8c5679b8097 100644
--- a/src/bin/pg_upgrade/info.c
+++ b/src/bin/pg_upgrade/info.c
@@ -53,8 +53,7 @@ gen_db_file_maps(DbInfo *old_db, DbInfo *new_db,
bool all_matched = true;
/* There will certainly not be more mappings than there are old rels */
- maps = (FileNameMap *) pg_malloc(sizeof(FileNameMap) *
- old_db->rel_arr.nrels);
+ maps = pg_malloc_array(FileNameMap, old_db->rel_arr.nrels);
/*
* Each of the RelInfo arrays should be sorted by OID. Scan through them
@@ -364,7 +363,7 @@ get_template0_info(ClusterInfo *cluster)
if (PQntuples(dbres) != 1)
pg_fatal("template0 not found");
- locale = pg_malloc(sizeof(DbLocaleInfo));
+ locale = pg_malloc_object(DbLocaleInfo);
i_datencoding = PQfnumber(dbres, "encoding");
i_datlocprovider = PQfnumber(dbres, "datlocprovider");
@@ -433,7 +432,7 @@ get_db_infos(ClusterInfo *cluster)
i_spclocation = PQfnumber(res, "spclocation");
ntups = PQntuples(res);
- dbinfos = (DbInfo *) pg_malloc0(sizeof(DbInfo) * ntups);
+ dbinfos = pg_malloc0_array(DbInfo, ntups);
for (tupnum = 0; tupnum < ntups; tupnum++)
{
@@ -579,7 +578,7 @@ static void
process_rel_infos(DbInfo *dbinfo, PGresult *res, void *arg)
{
int ntups = PQntuples(res);
- RelInfo *relinfos = (RelInfo *) pg_malloc(sizeof(RelInfo) * ntups);
+ RelInfo *relinfos = pg_malloc_array(RelInfo, ntups);
int i_reloid = PQfnumber(res, "reloid");
int i_indtable = PQfnumber(res, "indtable");
int i_toastheap = PQfnumber(res, "toastheap");
@@ -785,7 +784,7 @@ process_old_cluster_logical_slot_infos(DbInfo *dbinfo, PGresult *res, void *arg)
int i_caught_up;
int i_invalid;
- slotinfos = (LogicalSlotInfo *) pg_malloc(sizeof(LogicalSlotInfo) * num_slots);
+ slotinfos = pg_malloc_array(LogicalSlotInfo, num_slots);
i_slotname = PQfnumber(res, "slot_name");
i_plugin = PQfnumber(res, "plugin");
diff --git a/src/bin/pg_upgrade/parallel.c b/src/bin/pg_upgrade/parallel.c
index 6945f71fcf1..f0406de84ee 100644
--- a/src/bin/pg_upgrade/parallel.c
+++ b/src/bin/pg_upgrade/parallel.c
@@ -85,13 +85,13 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
/* parallel */
#ifdef WIN32
if (thread_handles == NULL)
- thread_handles = pg_malloc(user_opts.jobs * sizeof(HANDLE));
+ thread_handles = pg_malloc_array(HANDLE, user_opts.jobs);
if (exec_thread_args == NULL)
{
int i;
- exec_thread_args = pg_malloc(user_opts.jobs * sizeof(exec_thread_arg *));
+ exec_thread_args = pg_malloc_array(exec_thread_arg *, user_opts.jobs);
/*
* For safety and performance, we keep the args allocated during
@@ -99,7 +99,7 @@ parallel_exec_prog(const char *log_file, const char *opt_log_file,
* thread different from the one that allocated it.
*/
for (i = 0; i < user_opts.jobs; i++)
- exec_thread_args[i] = pg_malloc0(sizeof(exec_thread_arg));
+ exec_thread_args[i] = pg_malloc0_object(exec_thread_arg);
}
cur_thread_args = (void **) exec_thread_args;
@@ -188,13 +188,13 @@ parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
/* parallel */
#ifdef WIN32
if (thread_handles == NULL)
- thread_handles = pg_malloc(user_opts.jobs * sizeof(HANDLE));
+ thread_handles = pg_malloc_array(HANDLE, user_opts.jobs);
if (transfer_thread_args == NULL)
{
int i;
- transfer_thread_args = pg_malloc(user_opts.jobs * sizeof(transfer_thread_arg *));
+ transfer_thread_args = pg_malloc_array(transfer_thread_arg *, user_opts.jobs);
/*
* For safety and performance, we keep the args allocated during
@@ -202,7 +202,7 @@ parallel_transfer_all_new_dbs(DbInfoArr *old_db_arr, DbInfoArr *new_db_arr,
* thread different from the one that allocated it.
*/
for (i = 0; i < user_opts.jobs; i++)
- transfer_thread_args[i] = pg_malloc0(sizeof(transfer_thread_arg));
+ transfer_thread_args[i] = pg_malloc0_object(transfer_thread_arg);
}
cur_thread_args = (void **) transfer_thread_args;
diff --git a/src/bin/pg_upgrade/slru_io.c b/src/bin/pg_upgrade/slru_io.c
index ae3e224d7b1..2188a287850 100644
--- a/src/bin/pg_upgrade/slru_io.c
+++ b/src/bin/pg_upgrade/slru_io.c
@@ -26,7 +26,7 @@ static void SlruFlush(SlruSegState *state);
static SlruSegState *
AllocSlruSegState(const char *dir)
{
- SlruSegState *state = pg_malloc(sizeof(*state));
+ SlruSegState *state = pg_malloc_object(SlruSegState);
state->dir = pstrdup(dir);
state->fn = NULL;
diff --git a/src/bin/pg_upgrade/tablespace.c b/src/bin/pg_upgrade/tablespace.c
index 0ec5644a639..95ea7819457 100644
--- a/src/bin/pg_upgrade/tablespace.c
+++ b/src/bin/pg_upgrade/tablespace.c
@@ -69,9 +69,9 @@ get_tablespace_paths(void)
if (PQntuples(res) != 0)
{
old_cluster.tablespaces =
- (char **) pg_malloc(old_cluster.num_tablespaces * sizeof(char *));
+ pg_malloc_array(char *, old_cluster.num_tablespaces);
new_cluster.tablespaces =
- (char **) pg_malloc(new_cluster.num_tablespaces * sizeof(char *));
+ pg_malloc_array(char *, new_cluster.num_tablespaces);
}
else
{
diff --git a/src/bin/pg_upgrade/task.c b/src/bin/pg_upgrade/task.c
index 3d958527528..b6eb29e1f3a 100644
--- a/src/bin/pg_upgrade/task.c
+++ b/src/bin/pg_upgrade/task.c
@@ -116,7 +116,7 @@ typedef struct UpgradeTaskSlot
UpgradeTask *
upgrade_task_create(void)
{
- UpgradeTask *task = pg_malloc0(sizeof(UpgradeTask));
+ UpgradeTask *task = pg_malloc0_object(UpgradeTask);
task->queries = createPQExpBuffer();
@@ -154,8 +154,8 @@ upgrade_task_add_step(UpgradeTask *task, const char *query,
{
UpgradeTaskStep *new_step;
- task->steps = pg_realloc(task->steps,
- ++task->num_steps * sizeof(UpgradeTaskStep));
+ task->steps = pg_realloc_array(task->steps, UpgradeTaskStep,
+ ++task->num_steps);
new_step = &task->steps[task->num_steps - 1];
new_step->process_cb = process_cb;
@@ -421,7 +421,7 @@ void
upgrade_task_run(const UpgradeTask *task, const ClusterInfo *cluster)
{
int jobs = Max(1, user_opts.jobs);
- UpgradeTaskSlot *slots = pg_malloc0(sizeof(UpgradeTaskSlot) * jobs);
+ UpgradeTaskSlot *slots = pg_malloc0_array(UpgradeTaskSlot, jobs);
dbs_complete = 0;
dbs_processing = 0;
diff --git a/src/bin/pg_verifybackup/astreamer_verify.c b/src/bin/pg_verifybackup/astreamer_verify.c
index 0edc8123b43..26c98186530 100644
--- a/src/bin/pg_verifybackup/astreamer_verify.c
+++ b/src/bin/pg_verifybackup/astreamer_verify.c
@@ -79,7 +79,7 @@ astreamer_verify_content_new(astreamer *next, verifier_context *context,
streamer->tblspc_oid = tblspc_oid;
if (!context->skip_checksums)
- streamer->checksum_ctx = pg_malloc(sizeof(pg_checksum_context));
+ streamer->checksum_ctx = pg_malloc_object(pg_checksum_context);
return &streamer->base;
}
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index f9f2d457f2f..cbc9447384f 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -418,7 +418,7 @@ parse_manifest_file(char *manifest_path)
/* Create the hash table. */
ht = manifest_files_create(initial_size, NULL);
- result = pg_malloc0(sizeof(manifest_data));
+ result = pg_malloc0_object(manifest_data);
result->files = ht;
context.private_data = result;
context.version_cb = verifybackup_version_cb;
@@ -970,7 +970,7 @@ precheck_tar_backup_file(verifier_context *context, char *relpath,
* Append the information to the list for complete verification at a later
* stage.
*/
- tar = pg_malloc(sizeof(tar_file));
+ tar = pg_malloc_object(tar_file);
tar->relpath = pstrdup(relpath);
tar->tblspc_oid = tblspc_oid;
tar->compress_algorithm = compress_algorithm;
@@ -1065,7 +1065,7 @@ verify_backup_checksums(verifier_context *context)
progress_report(false);
- buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));
+ buffer = pg_malloc_array(uint8, READ_CHUNK_SIZE);
manifest_files_start_iterate(manifest->files, &it);
while ((m = manifest_files_iterate(manifest->files, &it)) != NULL)
diff --git a/src/bin/pgbench/exprparse.y b/src/bin/pgbench/exprparse.y
index 8dd6c8811f2..6dd809950fd 100644
--- a/src/bin/pgbench/exprparse.y
+++ b/src/bin/pgbench/exprparse.y
@@ -167,7 +167,7 @@ function: FUNCTION { $$ = find_func(yyscanner, $1); pg_free($1); }
static PgBenchExpr *
make_null_constant(void)
{
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
expr->etype = ENODE_CONSTANT;
expr->u.constant.type = PGBT_NULL;
@@ -178,7 +178,7 @@ make_null_constant(void)
static PgBenchExpr *
make_integer_constant(int64 ival)
{
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
expr->etype = ENODE_CONSTANT;
expr->u.constant.type = PGBT_INT;
@@ -189,7 +189,7 @@ make_integer_constant(int64 ival)
static PgBenchExpr *
make_double_constant(double dval)
{
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
expr->etype = ENODE_CONSTANT;
expr->u.constant.type = PGBT_DOUBLE;
@@ -200,7 +200,7 @@ make_double_constant(double dval)
static PgBenchExpr *
make_boolean_constant(bool bval)
{
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
expr->etype = ENODE_CONSTANT;
expr->u.constant.type = PGBT_BOOLEAN;
@@ -211,7 +211,7 @@ make_boolean_constant(bool bval)
static PgBenchExpr *
make_variable(char *varname)
{
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
expr->etype = ENODE_VARIABLE;
expr->u.variable.varname = varname;
@@ -415,12 +415,12 @@ make_elist(PgBenchExpr *expr, PgBenchExprList *list)
if (list == NULL)
{
- list = pg_malloc(sizeof(PgBenchExprList));
+ list = pg_malloc_object(PgBenchExprList);
list->head = NULL;
list->tail = NULL;
}
- cons = pg_malloc(sizeof(PgBenchExprLink));
+ cons = pg_malloc_object(PgBenchExprLink);
cons->expr = expr;
cons->next = NULL;
@@ -453,7 +453,7 @@ make_func(yyscan_t yyscanner, int fnumber, PgBenchExprList *args)
{
int len = elist_length(args);
- PgBenchExpr *expr = pg_malloc(sizeof(PgBenchExpr));
+ PgBenchExpr *expr = pg_malloc_object(PgBenchExpr);
Assert(fnumber >= 0);
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index cb4e986092e..1dae918cc09 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -1774,7 +1774,7 @@ enlargeVariables(Variables *variables, int needed)
{
variables->max_vars = needed + VARIABLES_ALLOC_MARGIN;
variables->vars = (Variable *)
- pg_realloc(variables->vars, variables->max_vars * sizeof(Variable));
+ pg_realloc_array(variables->vars, Variable, variables->max_vars);
}
}
@@ -3067,7 +3067,7 @@ allocCStatePrepared(CState *st)
{
Assert(st->prepared == NULL);
- st->prepared = pg_malloc(sizeof(bool *) * num_scripts);
+ st->prepared = pg_malloc_array(bool *, num_scripts);
for (int i = 0; i < num_scripts; i++)
{
ParsedScript *script = &sql_script[i];
@@ -3075,7 +3075,7 @@ allocCStatePrepared(CState *st)
for (numcmds = 0; script->commands[numcmds] != NULL; numcmds++)
;
- st->prepared[i] = pg_malloc0(sizeof(bool) * numcmds);
+ st->prepared[i] = pg_malloc0_array(bool, numcmds);
}
}
@@ -5659,7 +5659,7 @@ create_sql_command(PQExpBuffer buf)
return NULL;
/* Allocate and initialize Command structure */
- my_command = (Command *) pg_malloc(sizeof(Command));
+ my_command = pg_malloc0_object(Command);
initPQExpBuffer(&my_command->lines);
appendPQExpBufferStr(&my_command->lines, p);
my_command->first_line = NULL; /* this is set later */
@@ -5755,7 +5755,7 @@ process_backslash_command(PsqlScanState sstate, const char *source,
}
/* Allocate and initialize Command structure */
- my_command = (Command *) pg_malloc0(sizeof(Command));
+ my_command = pg_malloc0_object(Command);
my_command->type = META_COMMAND;
my_command->argc = 0;
initSimpleStats(&my_command->stats);
@@ -6011,7 +6011,7 @@ ParseScript(const char *script, const char *desc, int weight)
/* Initialize all fields of ps */
ps.desc = desc;
ps.weight = weight;
- ps.commands = (Command **) pg_malloc(sizeof(Command *) * alloc_num);
+ ps.commands = pg_malloc_array(Command *, alloc_num);
initStats(&ps.stats, 0);
/* Prepare to parse script */
@@ -6114,7 +6114,7 @@ ParseScript(const char *script, const char *desc, int weight)
{
alloc_num += COMMANDS_ALLOC_NUM;
ps.commands = (Command **)
- pg_realloc(ps.commands, sizeof(Command *) * alloc_num);
+ pg_realloc_array(ps.commands, Command *, alloc_num);
}
/* Done if we reached EOF */
@@ -6844,7 +6844,7 @@ main(int argc, char **argv)
}
}
- state = (CState *) pg_malloc0(sizeof(CState));
+ state = pg_malloc0_object(CState);
/* set random seed early, because it may be used while parsing scripts. */
if (!set_random_seed(getenv("PGBENCH_RANDOM_SEED")))
@@ -7298,7 +7298,7 @@ main(int argc, char **argv)
if (nclients > 1)
{
- state = (CState *) pg_realloc(state, sizeof(CState) * nclients);
+ state = pg_realloc_array(state, CState, nclients);
memset(state + 1, 0, sizeof(CState) * (nclients - 1));
/* copy any -D switch values to all clients */
@@ -7412,7 +7412,7 @@ main(int argc, char **argv)
PQfinish(con);
/* set up thread data structures */
- threads = (TState *) pg_malloc(sizeof(TState) * nthreads);
+ threads = pg_malloc_array(TState, nthreads);
nclients_dealt = 0;
for (i = 0; i < nthreads; i++)
@@ -7993,7 +7993,7 @@ socket_has_input(socket_set *sa, int fd, int idx)
static socket_set *
alloc_socket_set(int count)
{
- return (socket_set *) pg_malloc0(sizeof(socket_set));
+ return pg_malloc0_object(socket_set);
}
static void
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 213d48500de..637f2703db2 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -4168,8 +4168,8 @@ do_connect(enum trivalue reuse_previous_specification,
/* Loop till we have a connection or fail, which we might've already */
while (success)
{
- const char **keywords = pg_malloc((nconnopts + 1) * sizeof(*keywords));
- const char **values = pg_malloc((nconnopts + 1) * sizeof(*values));
+ const char **keywords = pg_malloc_array(const char *, nconnopts + 1);
+ const char **values = pg_malloc_array(const char *, nconnopts + 1);
int paramnum = 0;
PQconninfoOption *ci;
@@ -5665,7 +5665,7 @@ savePsetInfo(const printQueryOpt *popt)
{
printQueryOpt *save;
- save = (printQueryOpt *) pg_malloc(sizeof(printQueryOpt));
+ save = pg_malloc_object(printQueryOpt);
/* Flat-copy all the scalar fields, then duplicate sub-structures. */
memcpy(save, popt, sizeof(printQueryOpt));
diff --git a/src/bin/psql/copy.c b/src/bin/psql/copy.c
index 892c28894ed..6a8a9792e7d 100644
--- a/src/bin/psql/copy.c
+++ b/src/bin/psql/copy.c
@@ -99,7 +99,7 @@ parse_slash_copy(const char *args)
return NULL;
}
- result = pg_malloc0(sizeof(struct copy_options));
+ result = pg_malloc0_object(struct copy_options);
result->before_tofrom = pg_strdup(""); /* initialize for appending */
diff --git a/src/bin/psql/crosstabview.c b/src/bin/psql/crosstabview.c
index 3b268e41641..111e8823bdb 100644
--- a/src/bin/psql/crosstabview.c
+++ b/src/bin/psql/crosstabview.c
@@ -245,11 +245,9 @@ PrintResultInCrosstab(const PGresult *res)
num_columns = piv_columns.count;
num_rows = piv_rows.count;
- array_columns = (pivot_field *)
- pg_malloc(sizeof(pivot_field) * num_columns);
+ array_columns = pg_malloc_array(pivot_field, num_columns);
- array_rows = (pivot_field *)
- pg_malloc(sizeof(pivot_field) * num_rows);
+ array_rows = pg_malloc_array(pivot_field, num_rows);
avlCollectFields(&piv_columns, piv_columns.root, array_columns, 0);
avlCollectFields(&piv_rows, piv_rows.root, array_rows, 0);
@@ -312,7 +310,7 @@ printCrosstab(const PGresult *result,
* map associating each piv_columns[].rank to its index in piv_columns.
* This avoids an O(N^2) loop later.
*/
- horiz_map = (int *) pg_malloc(sizeof(int) * num_columns);
+ horiz_map = pg_malloc_array(int, num_columns);
for (i = 0; i < num_columns; i++)
horiz_map[piv_columns[i].rank] = i;
@@ -437,7 +435,7 @@ error:
static void
avlInit(avl_tree *tree)
{
- tree->end = (avl_node *) pg_malloc0(sizeof(avl_node));
+ tree->end = pg_malloc0_object(avl_node);
tree->end->children[0] = tree->end->children[1] = tree->end;
tree->count = 0;
tree->root = tree->end;
@@ -532,8 +530,7 @@ avlInsertNode(avl_tree *tree, avl_node **node, pivot_field field)
if (current == tree->end)
{
- avl_node *new_node = (avl_node *)
- pg_malloc(sizeof(avl_node));
+ avl_node *new_node = pg_malloc_object(avl_node);
new_node->height = 1;
new_node->field = field;
@@ -591,7 +588,7 @@ rankSort(int num_columns, pivot_field *piv_columns)
* every header entry] */
int i;
- hmap = (int *) pg_malloc(sizeof(int) * num_columns * 2);
+ hmap = pg_malloc_array(int, num_columns * 2);
for (i = 0; i < num_columns; i++)
{
char *val = piv_columns[i].sort_value;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 571a6a003d5..4352991e541 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3797,7 +3797,7 @@ describeRoles(const char *pattern, bool verbose, bool showSystem)
return false;
nrows = PQntuples(res);
- attr = pg_malloc0((nrows + 1) * sizeof(*attr));
+ attr = pg_malloc0_array(char *, nrows + 1);
printTableInit(&cont, &myopt, _("List of roles"), ncols, nrows);
@@ -5306,7 +5306,7 @@ listSchemas(const char *pattern, bool verbose, bool showSystem)
* storing "Publications:" string) + publication schema mapping
* count + 1 (for storing NULL).
*/
- footers = (char **) pg_malloc((1 + pub_schema_tuples + 1) * sizeof(char *));
+ footers = pg_malloc_array(char *, 1 + pub_schema_tuples + 1);
footers[0] = pg_strdup(_("Publications:"));
/* Might be an empty set - that's ok */
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 8b91bc00062..b2dba6d10ab 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -6324,8 +6324,7 @@ append_variable_names(char ***varnames, int *nvars,
if (*nvars >= *maxvars)
{
*maxvars *= 2;
- *varnames = (char **) pg_realloc(*varnames,
- ((*maxvars) + 1) * sizeof(char *));
+ *varnames = pg_realloc_array(*varnames, char *, (*maxvars) + 1);
}
(*varnames)[(*nvars)++] = psprintf("%s%s%s", prefix, varname, suffix);
@@ -6350,7 +6349,7 @@ complete_from_variables(const char *text, const char *prefix, const char *suffix
int i;
struct _variable *ptr;
- varnames = (char **) pg_malloc((maxvars + 1) * sizeof(char *));
+ varnames = pg_malloc_array(char *, maxvars + 1);
for (ptr = pset.vars->next; ptr; ptr = ptr->next)
{
@@ -6928,7 +6927,7 @@ get_previous_words(int point, char **buffer, int *nwords)
* This is usually much more space than we need, but it's cheaper than
* doing a separate malloc() for each word.
*/
- previous_words = (char **) pg_malloc(point * sizeof(char *));
+ previous_words = pg_malloc_array(char *, point);
*buffer = outptr = (char *) pg_malloc(point * 2);
/*
diff --git a/src/bin/psql/variables.c b/src/bin/psql/variables.c
index 1cd082db157..f2a28bc9820 100644
--- a/src/bin/psql/variables.c
+++ b/src/bin/psql/variables.c
@@ -54,7 +54,7 @@ CreateVariableSpace(void)
{
struct _variable *ptr;
- ptr = pg_malloc(sizeof *ptr);
+ ptr = pg_malloc_object(struct _variable);
ptr->name = NULL;
ptr->value = NULL;
ptr->substitute_hook = NULL;
@@ -353,7 +353,7 @@ SetVariable(VariableSpace space, const char *name, const char *value)
/* not present, make new entry ... unless we were asked to delete */
if (value)
{
- current = pg_malloc(sizeof *current);
+ current = pg_malloc_object(struct _variable);
current->name = pg_strdup(name);
current->value = pg_strdup(value);
current->substitute_hook = NULL;
@@ -416,7 +416,7 @@ SetVariableHooks(VariableSpace space, const char *name,
}
/* not present, make new entry */
- current = pg_malloc(sizeof *current);
+ current = pg_malloc_object(struct _variable);
current->name = pg_strdup(name);
current->value = NULL;
current->substitute_hook = shook;
diff --git a/src/bin/scripts/reindexdb.c b/src/bin/scripts/reindexdb.c
index 8bab74b5917..d7fb16d3c85 100644
--- a/src/bin/scripts/reindexdb.c
+++ b/src/bin/scripts/reindexdb.c
@@ -322,7 +322,7 @@ reindex_one_database(ConnParams *cparams, ReindexType type,
* database itself, so build a list with a single entry.
*/
Assert(user_list == NULL);
- process_list = pg_malloc0(sizeof(SimpleStringList));
+ process_list = pg_malloc0_object(SimpleStringList);
simple_string_list_append(process_list, PQdb(conn));
break;
@@ -713,7 +713,7 @@ get_parallel_tables_list(PGconn *conn, ReindexType type,
return NULL;
}
- tables = pg_malloc0(sizeof(SimpleStringList));
+ tables = pg_malloc0_object(SimpleStringList);
/* Build qualified identifiers for each table */
for (int i = 0; i < ntups; i++)
@@ -809,7 +809,7 @@ get_parallel_tabidx_list(PGconn *conn,
return;
}
- *table_list = pg_malloc0(sizeof(SimpleOidList));
+ *table_list = pg_malloc0_object(SimpleOidList);
/*
* Build two lists, one with table OIDs and the other with fully-qualified
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index a0aec04d994..440c875b8ac 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -147,7 +147,7 @@ main(int argc, char **argv)
* extra for lock wait detection and global work.
*/
nconns = 1 + testspec->nsessions;
- conns = (IsoConnInfo *) pg_malloc0(nconns * sizeof(IsoConnInfo));
+ conns = pg_malloc0_array(IsoConnInfo, nconns);
atexit(disconnect_atexit);
for (i = 0; i < nconns; i++)
@@ -262,7 +262,7 @@ check_testspec(TestSpec *testspec)
for (i = 0; i < testspec->nsessions; i++)
nallsteps += testspec->sessions[i]->nsteps;
- allsteps = pg_malloc(nallsteps * sizeof(Step *));
+ allsteps = pg_malloc_array(Step *, nallsteps);
k = 0;
for (i = 0; i < testspec->nsessions; i++)
@@ -417,8 +417,8 @@ run_all_permutations(TestSpec *testspec)
nsteps += testspec->sessions[i]->nsteps;
/* Create PermutationStep workspace array */
- steps = (PermutationStep *) pg_malloc0(sizeof(PermutationStep) * nsteps);
- stepptrs = (PermutationStep **) pg_malloc(sizeof(PermutationStep *) * nsteps);
+ steps = pg_malloc0_array(PermutationStep, nsteps);
+ stepptrs = pg_malloc_array(PermutationStep *, nsteps);
for (i = 0; i < nsteps; i++)
stepptrs[i] = steps + i;
@@ -431,7 +431,7 @@ run_all_permutations(TestSpec *testspec)
* A pile is actually just an integer which tells how many steps we've
* already picked from this pile.
*/
- piles = pg_malloc(sizeof(int) * testspec->nsessions);
+ piles = pg_malloc_array(int, testspec->nsessions);
for (i = 0; i < testspec->nsessions; i++)
piles[i] = 0;
@@ -524,7 +524,7 @@ run_permutation(TestSpec *testspec, int nsteps, PermutationStep **steps)
int nwaiting = 0;
PermutationStep **waiting;
- waiting = pg_malloc(sizeof(PermutationStep *) * testspec->nsessions);
+ waiting = pg_malloc_array(PermutationStep *, testspec->nsessions);
printf("\nstarting permutation:");
for (i = 0; i < nsteps; i++)
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index b61d789d8f0..f6b9058e557 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -83,8 +83,8 @@ setup_list:
}
| setup_list setup
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $2;
$$.nelements = $1.nelements + 1;
}
@@ -107,15 +107,15 @@ opt_teardown:
session_list:
session_list session
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $2;
$$.nelements = $1.nelements + 1;
}
| session
{
$$.nelements = 1;
- $$.elements = pg_malloc(sizeof(void *));
+ $$.elements = pg_malloc_object(void *);
$$.elements[0] = $1;
}
;
@@ -123,7 +123,7 @@ session_list:
session:
SESSION identifier opt_setup step_list opt_teardown
{
- $$ = pg_malloc(sizeof(Session));
+ $$ = pg_malloc_object(Session);
$$->name = $2;
$$->setupsql = $3;
$$->steps = (Step **) $4.elements;
@@ -135,15 +135,15 @@ session:
step_list:
step_list step
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $2;
$$.nelements = $1.nelements + 1;
}
| step
{
$$.nelements = 1;
- $$.elements = pg_malloc(sizeof(void *));
+ $$.elements = pg_malloc_object(void *);
$$.elements[0] = $1;
}
;
@@ -152,7 +152,7 @@ step_list:
step:
STEP identifier sqlblock
{
- $$ = pg_malloc(sizeof(Step));
+ $$ = pg_malloc_object(Step);
$$->name = $2;
$$->sql = $3;
$$->session = -1; /* until filled */
@@ -175,15 +175,15 @@ opt_permutation_list:
permutation_list:
permutation_list permutation
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $2;
$$.nelements = $1.nelements + 1;
}
| permutation
{
$$.nelements = 1;
- $$.elements = pg_malloc(sizeof(void *));
+ $$.elements = pg_malloc_object(void *);
$$.elements[0] = $1;
}
;
@@ -192,7 +192,7 @@ permutation_list:
permutation:
PERMUTATION permutation_step_list
{
- $$ = pg_malloc(sizeof(Permutation));
+ $$ = pg_malloc_object(Permutation);
$$->nsteps = $2.nelements;
$$->steps = (PermutationStep **) $2.elements;
}
@@ -201,15 +201,15 @@ permutation:
permutation_step_list:
permutation_step_list permutation_step
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $2;
$$.nelements = $1.nelements + 1;
}
| permutation_step
{
$$.nelements = 1;
- $$.elements = pg_malloc(sizeof(void *));
+ $$.elements = pg_malloc_object(void *);
$$.elements[0] = $1;
}
;
@@ -217,7 +217,7 @@ permutation_step_list:
permutation_step:
identifier
{
- $$ = pg_malloc(sizeof(PermutationStep));
+ $$ = pg_malloc_object(PermutationStep);
$$->name = $1;
$$->blockers = NULL;
$$->nblockers = 0;
@@ -225,7 +225,7 @@ permutation_step:
}
| identifier '(' blocker_list ')'
{
- $$ = pg_malloc(sizeof(PermutationStep));
+ $$ = pg_malloc_object(PermutationStep);
$$->name = $1;
$$->blockers = (PermutationStepBlocker **) $3.elements;
$$->nblockers = $3.nelements;
@@ -236,15 +236,15 @@ permutation_step:
blocker_list:
blocker_list ',' blocker
{
- $$.elements = pg_realloc($1.elements,
- ($1.nelements + 1) * sizeof(void *));
+ $$.elements = pg_realloc_array($1.elements, void *,
+ $1.nelements + 1);
$$.elements[$1.nelements] = $3;
$$.nelements = $1.nelements + 1;
}
| blocker
{
$$.nelements = 1;
- $$.elements = pg_malloc(sizeof(void *));
+ $$.elements = pg_malloc_object(void *);
$$.elements[0] = $1;
}
;
@@ -252,7 +252,7 @@ blocker_list:
blocker:
identifier
{
- $$ = pg_malloc(sizeof(PermutationStepBlocker));
+ $$ = pg_malloc_object(PermutationStepBlocker);
$$->stepname = $1;
$$->blocktype = PSB_OTHER_STEP;
$$->num_notices = -1;
@@ -261,7 +261,7 @@ blocker:
}
| identifier NOTICES INTEGER
{
- $$ = pg_malloc(sizeof(PermutationStepBlocker));
+ $$ = pg_malloc_object(PermutationStepBlocker);
$$->stepname = $1;
$$->blocktype = PSB_NUM_NOTICES;
$$->num_notices = $3;
@@ -270,7 +270,7 @@ blocker:
}
| '*'
{
- $$ = pg_malloc(sizeof(PermutationStepBlocker));
+ $$ = pg_malloc_object(PermutationStepBlocker);
$$->stepname = NULL;
$$->blocktype = PSB_ONCE;
$$->num_notices = -1;
diff --git a/src/test/modules/libpq_pipeline/libpq_pipeline.c b/src/test/modules/libpq_pipeline/libpq_pipeline.c
index 409b3a7fa45..aa0a6bbe762 100644
--- a/src/test/modules/libpq_pipeline/libpq_pipeline.c
+++ b/src/test/modules/libpq_pipeline/libpq_pipeline.c
@@ -260,8 +260,8 @@ copy_connection(PGconn *conn)
nopts++;
nopts++; /* for the NULL terminator */
- keywords = pg_malloc(sizeof(char *) * nopts);
- vals = pg_malloc(sizeof(char *) * nopts);
+ keywords = pg_malloc_array(const char *, nopts);
+ vals = pg_malloc_array(const char *, nopts);
i = 0;
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
@@ -1337,8 +1337,8 @@ test_protocol_version(PGconn *conn)
nopts++;
nopts++; /* NULL terminator */
- keywords = pg_malloc0(sizeof(char *) * nopts);
- vals = pg_malloc0(sizeof(char *) * nopts);
+ keywords = pg_malloc0_array(const char *, nopts);
+ vals = pg_malloc0_array(const char *, nopts);
i = 0;
for (PQconninfoOption *opt = opts; opt->keyword != NULL; ++opt)
diff --git a/src/test/regress/pg_regress.c b/src/test/regress/pg_regress.c
index b5c0cb647a8..b8b6a911987 100644
--- a/src/test/regress/pg_regress.c
+++ b/src/test/regress/pg_regress.c
@@ -196,7 +196,7 @@ unlimit_core_size(void)
void
add_stringlist_item(_stringlist **listhead, const char *str)
{
- _stringlist *newentry = pg_malloc(sizeof(_stringlist));
+ _stringlist *newentry = pg_malloc_object(_stringlist);
_stringlist *oldentry;
newentry->str = pg_strdup(str);
@@ -674,7 +674,7 @@ load_resultmap(void)
*/
if (string_matches_pattern(host_platform, platform))
{
- _resultmap *entry = pg_malloc(sizeof(_resultmap));
+ _resultmap *entry = pg_malloc_object(_resultmap);
entry->test = pg_strdup(buf);
entry->type = pg_strdup(file_type);
@@ -1557,7 +1557,7 @@ wait_for_tests(PID_TYPE * pids, int *statuses, instr_time *stoptimes,
int i;
#ifdef WIN32
- PID_TYPE *active_pids = pg_malloc(num_tests * sizeof(PID_TYPE));
+ PID_TYPE *active_pids = pg_malloc_array(PID_TYPE, num_tests);
memcpy(active_pids, pids, num_tests * sizeof(PID_TYPE));
#endif
--
2.47.3
[text/x-patch] v1-0002-TODO-What-to-do-about-when-we-allocate-an-array-o.patch (2.9K, ../../[email protected]/3-v1-0002-TODO-What-to-do-about-when-we-allocate-an-array-o.patch)
download | inline diff:
From 1e6fcfa51df10912e665cc9bd583e49eb03f6f13 Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email protected]>
Date: Fri, 27 Feb 2026 02:11:17 +0100
Subject: [PATCH v1 2/3] TODO: What to do about when we allocate an array of
char?
---
contrib/oid2name/oid2name.c | 8 ++++----
src/bin/initdb/initdb.c | 4 ++--
src/bin/pg_basebackup/walmethods.c | 2 +-
3 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/contrib/oid2name/oid2name.c b/contrib/oid2name/oid2name.c
index 1e9efcd3953..cfa342a2926 100644
--- a/contrib/oid2name/oid2name.c
+++ b/contrib/oid2name/oid2name.c
@@ -275,7 +275,7 @@ get_comma_elts(eary *eary)
for (i = 0; i < eary->num; i++)
length += strlen(eary->array[i]);
- ret = (char *) pg_malloc(length * 2 + 4 * eary->num);
+ ret = pg_malloc_array(char, length * 2 + 4 * eary->num);
ptr = ret;
for (i = 0; i < eary->num; i++)
@@ -423,7 +423,7 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
l += length[j] + 2;
}
fprintf(stdout, "\n");
- pad = (char *) pg_malloc(l + 1);
+ pad = pg_malloc_array(char, l + 1);
memset(pad, '-', l);
pad[l] = '\0';
fprintf(stdout, "%s\n", pad);
@@ -515,8 +515,8 @@ sql_exec_searchtables(PGconn *conn, struct options *opts)
comma_filenumbers = get_comma_elts(opts->filenumbers);
/* 80 extra chars for SQL expression */
- qualifiers = (char *) pg_malloc(strlen(comma_oids) + strlen(comma_tables) +
- strlen(comma_filenumbers) + 80);
+ qualifiers = pg_malloc_array(char, strlen(comma_oids) + strlen(comma_tables) +
+ strlen(comma_filenumbers) + 80);
ptr = qualifiers;
if (opts->oids->num > 0)
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 53ec1544ff3..b6916bad201 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -426,7 +426,7 @@ escape_quotes_bki(const char *src)
char *resultp;
char *datap;
- result = (char *) pg_malloc(strlen(data) + 3);
+ result = pg_malloc_array(char, strlen(data) + 3);
resultp = result;
*resultp++ = '\'';
for (datap = data; *datap; datap++)
@@ -492,7 +492,7 @@ replace_token(char **lines, const char *token, const char *replacement)
/* if we get here a change is needed - set up new line */
- newline = (char *) pg_malloc(strlen(lines[i]) + diff + 1);
+ newline = pg_malloc_array(char, strlen(lines[i]) + diff + 1);
pre = where - lines[i];
diff --git a/src/bin/pg_basebackup/walmethods.c b/src/bin/pg_basebackup/walmethods.c
index 476673cf729..3a6b3b5f45b 100644
--- a/src/bin/pg_basebackup/walmethods.c
+++ b/src/bin/pg_basebackup/walmethods.c
@@ -102,7 +102,7 @@ static char *
dir_get_file_name(WalWriteMethod *wwmethod,
const char *pathname, const char *temp_suffix)
{
- char *filename = pg_malloc0(MAXPGPATH * sizeof(char));
+ char *filename = pg_malloc0_array(char, MAXPGPATH);
snprintf(filename, MAXPGPATH, "%s%s%s",
pathname,
--
2.47.3
[text/x-patch] v1-0003-TODO-uint8-vs-char-confusion.patch (856B, ../../[email protected]/4-v1-0003-TODO-uint8-vs-char-confusion.patch)
download | inline diff:
From 2056a1f6c1422e0f2a56b4a832ddf92ecf8256ff Mon Sep 17 00:00:00 2001
From: Andreas Karlsson <[email protected]>
Date: Fri, 27 Feb 2026 02:11:30 +0100
Subject: [PATCH v1 3/3] TODO: uint8 vs char confusion
---
src/bin/pg_verifybackup/pg_verifybackup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/bin/pg_verifybackup/pg_verifybackup.c b/src/bin/pg_verifybackup/pg_verifybackup.c
index cbc9447384f..562e9212e30 100644
--- a/src/bin/pg_verifybackup/pg_verifybackup.c
+++ b/src/bin/pg_verifybackup/pg_verifybackup.c
@@ -1007,7 +1007,7 @@ verify_tar_file(verifier_context *context, char *relpath, char *fullpath,
return;
}
- buffer = pg_malloc(READ_CHUNK_SIZE * sizeof(uint8));
+ buffer = pg_malloc_array(char, READ_CHUNK_SIZE);
/* Perform the reads */
while ((rc = read(fd, buffer, READ_CHUNK_SIZE)) > 0)
--
2.47.3
^ permalink raw reply [nested|flat] 5+ messages in thread
end of thread, other threads:[~2026-02-27 01:15 UTC | newest]
Thread overview: 5+ messages (download: mbox mbox.gz follow: Atom feed)
-- links below jump to the message on this page --
2021-01-28 16:42 [PATCH v3 5/5] Do COPY FROM encoding conversion/verification in larger chunks. Heikki Linnakangas <[email protected]>
2026-02-18 15:05 Use pg_malloc macros in src/fe_utils Henrik TJ <[email protected]>
2026-02-23 02:17 ` Re: Use pg_malloc macros in src/fe_utils Andreas Karlsson <[email protected]>
2026-02-24 03:36 ` Re: Use pg_malloc macros in src/fe_utils Michael Paquier <[email protected]>
2026-02-27 01:15 ` Re: Use pg_malloc macros in src/fe_utils Andreas Karlsson <[email protected]>
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox