summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/datatype.sgml2
-rw-r--r--doc/src/sgml/logicaldecoding.sgml8
-rw-r--r--meson.build7
-rw-r--r--src/backend/backup/basebackup_copy.c14
-rw-r--r--src/backend/postmaster/checkpointer.c9
-rw-r--r--src/backend/replication/logical/applyparallelworker.c4
-rw-r--r--src/backend/replication/logical/worker.c10
-rw-r--r--src/backend/replication/walreceiver.c8
-rw-r--r--src/backend/replication/walsender.c25
-rw-r--r--src/backend/utils/activity/pgstat_shmem.c5
-rw-r--r--src/backend/utils/adt/numeric.c502
-rw-r--r--src/backend/utils/adt/timestamp.c2
-rw-r--r--src/bin/pg_basebackup/pg_basebackup.c9
-rw-r--r--src/bin/pg_basebackup/pg_recvlogical.c11
-rw-r--r--src/bin/pg_basebackup/receivelog.c11
-rw-r--r--src/bin/pg_upgrade/check.c2
-rw-r--r--src/include/common/int128.h323
-rw-r--r--src/include/libpq/protocol.h21
-rw-r--r--src/include/utils/pg_locale.h2
-rw-r--r--src/test/modules/test_int128/test_int128.c103
-rw-r--r--src/test/regress/expected/aggregates.out19
-rw-r--r--src/test/regress/expected/timestamp.out10
-rw-r--r--src/test/regress/expected/timestamptz.out18
-rw-r--r--src/test/regress/sql/aggregates.sql5
-rw-r--r--src/test/regress/sql/timestamp.sql4
-rw-r--r--src/test/regress/sql/timestamptz.sql7
26 files changed, 652 insertions, 489 deletions
diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index 0994e089311..7458f216e50 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -117,7 +117,7 @@
<row>
<entry><type>double precision</type></entry>
- <entry><type>float8</type></entry>
+ <entry><type>float</type>, <type>float8</type></entry>
<entry>double precision floating-point number (8 bytes)</entry>
</row>
diff --git a/doc/src/sgml/logicaldecoding.sgml b/doc/src/sgml/logicaldecoding.sgml
index 593f784b69d..77c720c422c 100644
--- a/doc/src/sgml/logicaldecoding.sgml
+++ b/doc/src/sgml/logicaldecoding.sgml
@@ -290,7 +290,7 @@ postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NU
<para>
A logical slot will emit each change just once in normal operation.
The current position of each slot is persisted only at checkpoint, so in
- the case of a crash the slot may return to an earlier LSN, which will
+ the case of a crash the slot might return to an earlier LSN, which will
then cause recent changes to be sent again when the server restarts.
Logical decoding clients are responsible for avoiding ill effects from
handling the same message more than once. Clients may wish to record
@@ -409,7 +409,7 @@ postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NU
should be used with caution. Unlike automatic synchronization, it does not
include cyclic retries, making it more prone to synchronization failures,
particularly during initial sync scenarios where the required WAL files
- or catalog rows for the slot may have already been removed or are at risk
+ or catalog rows for the slot might have already been removed or are at risk
of being removed on the standby. In contrast, automatic synchronization
via <varname>sync_replication_slots</varname> provides continuous slot
updates, enabling seamless failover and supporting high availability.
@@ -430,8 +430,8 @@ postgres=# select * from pg_logical_slot_get_changes('regression_slot', NULL, NU
standby, the slot will not be persisted to avoid data loss. In such
cases, the following log message may appear:
<programlisting>
- LOG: could not synchronize replication slot "failover_slot"
- DETAIL: Synchronization could lead to data loss as the remote slot needs WAL at LSN 0/03003F28 and catalog xmin 754, but the standby has LSN 0/03003F28 and catalog xmin 756
+LOG: could not synchronize replication slot "failover_slot"
+DETAIL: Synchronization could lead to data loss, because the remote slot needs WAL at LSN 0/03003F28 and catalog xmin 754, but the standby has LSN 0/03003F28 and catalog xmin 756.
</programlisting>
If the logical replication slot is actively used by a consumer, no
manual intervention is needed; the slot will advance automatically,
diff --git a/meson.build b/meson.build
index ca423dc8e12..431fe9ccc9b 100644
--- a/meson.build
+++ b/meson.build
@@ -3472,6 +3472,13 @@ installed_targets = [
ecpg_targets,
]
+if oauth_flow_supported
+ installed_targets += [
+ libpq_oauth_so,
+ libpq_oauth_st,
+ ]
+endif
+
# all targets that require building code
all_built = [
installed_targets,
diff --git a/src/backend/backup/basebackup_copy.c b/src/backend/backup/basebackup_copy.c
index 18b0b5a52d3..eb45d3bcb66 100644
--- a/src/backend/backup/basebackup_copy.c
+++ b/src/backend/backup/basebackup_copy.c
@@ -143,7 +143,7 @@ bbsink_copystream_begin_backup(bbsink *sink)
buf = palloc(mysink->base.bbs_buffer_length + MAXIMUM_ALIGNOF);
mysink->msgbuffer = buf + (MAXIMUM_ALIGNOF - 1);
mysink->base.bbs_buffer = buf + MAXIMUM_ALIGNOF;
- mysink->msgbuffer[0] = 'd'; /* archive or manifest data */
+ mysink->msgbuffer[0] = PqMsg_CopyData; /* archive or manifest data */
/* Tell client the backup start location. */
SendXlogRecPtrResult(state->startptr, state->starttli);
@@ -170,7 +170,7 @@ bbsink_copystream_begin_archive(bbsink *sink, const char *archive_name)
ti = list_nth(state->tablespaces, state->tablespace_num);
pq_beginmessage(&buf, PqMsg_CopyData);
- pq_sendbyte(&buf, 'n'); /* New archive */
+ pq_sendbyte(&buf, PqBackupMsg_NewArchive);
pq_sendstring(&buf, archive_name);
pq_sendstring(&buf, ti->path == NULL ? "" : ti->path);
pq_endmessage(&buf);
@@ -191,7 +191,7 @@ bbsink_copystream_archive_contents(bbsink *sink, size_t len)
if (mysink->send_to_client)
{
/* Add one because we're also sending a leading type byte. */
- pq_putmessage('d', mysink->msgbuffer, len + 1);
+ pq_putmessage(PqMsg_CopyData, mysink->msgbuffer, len + 1);
}
/* Consider whether to send a progress report to the client. */
@@ -221,7 +221,7 @@ bbsink_copystream_archive_contents(bbsink *sink, size_t len)
mysink->last_progress_report_time = now;
pq_beginmessage(&buf, PqMsg_CopyData);
- pq_sendbyte(&buf, 'p'); /* Progress report */
+ pq_sendbyte(&buf, PqBackupMsg_ProgressReport);
pq_sendint64(&buf, state->bytes_done);
pq_endmessage(&buf);
pq_flush_if_writable();
@@ -247,7 +247,7 @@ bbsink_copystream_end_archive(bbsink *sink)
mysink->bytes_done_at_last_time_check = state->bytes_done;
mysink->last_progress_report_time = GetCurrentTimestamp();
pq_beginmessage(&buf, PqMsg_CopyData);
- pq_sendbyte(&buf, 'p'); /* Progress report */
+ pq_sendbyte(&buf, PqBackupMsg_ProgressReport);
pq_sendint64(&buf, state->bytes_done);
pq_endmessage(&buf);
pq_flush_if_writable();
@@ -262,7 +262,7 @@ bbsink_copystream_begin_manifest(bbsink *sink)
StringInfoData buf;
pq_beginmessage(&buf, PqMsg_CopyData);
- pq_sendbyte(&buf, 'm'); /* Manifest */
+ pq_sendbyte(&buf, PqBackupMsg_Manifest);
pq_endmessage(&buf);
}
@@ -277,7 +277,7 @@ bbsink_copystream_manifest_contents(bbsink *sink, size_t len)
if (mysink->send_to_client)
{
/* Add one because we're also sending a leading type byte. */
- pq_putmessage('d', mysink->msgbuffer, len + 1);
+ pq_putmessage(PqMsg_CopyData, mysink->msgbuffer, len + 1);
}
}
diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c
index 8490148a47d..e84e8663e96 100644
--- a/src/backend/postmaster/checkpointer.c
+++ b/src/backend/postmaster/checkpointer.c
@@ -953,11 +953,14 @@ CheckpointerShmemSize(void)
Size size;
/*
- * Currently, the size of the requests[] array is arbitrarily set equal to
- * NBuffers. This may prove too large or small ...
+ * The size of the requests[] array is arbitrarily set equal to NBuffers.
+ * But there is a cap of MAX_CHECKPOINT_REQUESTS to prevent accumulating
+ * too many checkpoint requests in the ring buffer.
*/
size = offsetof(CheckpointerShmemStruct, requests);
- size = add_size(size, mul_size(NBuffers, sizeof(CheckpointerRequest)));
+ size = add_size(size, mul_size(Min(NBuffers,
+ MAX_CHECKPOINT_REQUESTS),
+ sizeof(CheckpointerRequest)));
return size;
}
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 1fa931a7422..cd0e19176fd 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -778,10 +778,10 @@ LogicalParallelApplyLoop(shm_mq_handle *mqh)
/*
* The first byte of messages sent from leader apply worker to
- * parallel apply workers can only be 'w'.
+ * parallel apply workers can only be PqReplMsg_WALData.
*/
c = pq_getmsgbyte(&s);
- if (c != 'w')
+ if (c != PqReplMsg_WALData)
elog(ERROR, "unexpected message \"%c\"", c);
/*
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 89e241c8392..0fdc5de57ba 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3994,7 +3994,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
c = pq_getmsgbyte(&s);
- if (c == 'w')
+ if (c == PqReplMsg_WALData)
{
XLogRecPtr start_lsn;
XLogRecPtr end_lsn;
@@ -4016,7 +4016,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
maybe_advance_nonremovable_xid(&rdt_data, false);
}
- else if (c == 'k')
+ else if (c == PqReplMsg_Keepalive)
{
XLogRecPtr end_lsn;
TimestampTz timestamp;
@@ -4035,7 +4035,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
UpdateWorkerStats(last_received, timestamp, true);
}
- else if (c == 's') /* Primary status update */
+ else if (c == PqReplMsg_PrimaryStatusUpdate)
{
rdt_data.remote_lsn = pq_getmsgint64(&s);
rdt_data.remote_oldestxid = FullTransactionIdFromU64((uint64) pq_getmsgint64(&s));
@@ -4267,7 +4267,7 @@ send_feedback(XLogRecPtr recvpos, bool force, bool requestReply)
else
resetStringInfo(reply_message);
- pq_sendbyte(reply_message, 'r');
+ pq_sendbyte(reply_message, PqReplMsg_StandbyStatusUpdate);
pq_sendint64(reply_message, recvpos); /* write */
pq_sendint64(reply_message, flushpos); /* flush */
pq_sendint64(reply_message, writepos); /* apply */
@@ -4438,7 +4438,7 @@ request_publisher_status(RetainDeadTuplesData *rdt_data)
* Send the current time to update the remote walsender's latest reply
* message received time.
*/
- pq_sendbyte(request_message, 'p');
+ pq_sendbyte(request_message, PqReplMsg_PrimaryStatusRequest);
pq_sendint64(request_message, GetCurrentTimestamp());
elog(DEBUG2, "sending publisher status request message");
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index b6281101711..7361ffc9dcf 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -826,7 +826,7 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
switch (type)
{
- case 'w': /* WAL records */
+ case PqReplMsg_WALData:
{
StringInfoData incoming_message;
@@ -850,7 +850,7 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
XLogWalRcvWrite(buf, len, dataStart, tli);
break;
}
- case 'k': /* Keepalive */
+ case PqReplMsg_Keepalive:
{
StringInfoData incoming_message;
@@ -1130,7 +1130,7 @@ XLogWalRcvSendReply(bool force, bool requestReply)
applyPtr = GetXLogReplayRecPtr(NULL);
resetStringInfo(&reply_message);
- pq_sendbyte(&reply_message, 'r');
+ pq_sendbyte(&reply_message, PqReplMsg_StandbyStatusUpdate);
pq_sendint64(&reply_message, writePtr);
pq_sendint64(&reply_message, flushPtr);
pq_sendint64(&reply_message, applyPtr);
@@ -1234,7 +1234,7 @@ XLogWalRcvSendHSFeedback(bool immed)
/* Construct the message and send it. */
resetStringInfo(&reply_message);
- pq_sendbyte(&reply_message, 'h');
+ pq_sendbyte(&reply_message, PqReplMsg_HotStandbyFeedback);
pq_sendint64(&reply_message, GetCurrentTimestamp());
pq_sendint32(&reply_message, xmin);
pq_sendint32(&reply_message, xmin_epoch);
diff --git a/src/backend/replication/walsender.c b/src/backend/replication/walsender.c
index ee911394a23..0855bae3535 100644
--- a/src/backend/replication/walsender.c
+++ b/src/backend/replication/walsender.c
@@ -1534,7 +1534,7 @@ WalSndPrepareWrite(LogicalDecodingContext *ctx, XLogRecPtr lsn, TransactionId xi
resetStringInfo(ctx->out);
- pq_sendbyte(ctx->out, 'w');
+ pq_sendbyte(ctx->out, PqReplMsg_WALData);
pq_sendint64(ctx->out, lsn); /* dataStart */
pq_sendint64(ctx->out, lsn); /* walEnd */
@@ -2292,7 +2292,8 @@ ProcessRepliesIfAny(void)
switch (firstchar)
{
/*
- * 'd' means a standby reply wrapped in a CopyData packet.
+ * PqMsg_CopyData means a standby reply wrapped in a CopyData
+ * packet.
*/
case PqMsg_CopyData:
ProcessStandbyMessage();
@@ -2300,8 +2301,9 @@ ProcessRepliesIfAny(void)
break;
/*
- * CopyDone means the standby requested to finish streaming.
- * Reply with CopyDone, if we had not sent that already.
+ * PqMsg_CopyDone means the standby requested to finish
+ * streaming. Reply with CopyDone, if we had not sent that
+ * already.
*/
case PqMsg_CopyDone:
if (!streamingDoneSending)
@@ -2315,7 +2317,8 @@ ProcessRepliesIfAny(void)
break;
/*
- * 'X' means that the standby is closing down the socket.
+ * PqMsg_Terminate means that the standby is closing down the
+ * socket.
*/
case PqMsg_Terminate:
proc_exit(0);
@@ -2350,15 +2353,15 @@ ProcessStandbyMessage(void)
switch (msgtype)
{
- case 'r':
+ case PqReplMsg_StandbyStatusUpdate:
ProcessStandbyReplyMessage();
break;
- case 'h':
+ case PqReplMsg_HotStandbyFeedback:
ProcessStandbyHSFeedbackMessage();
break;
- case 'p':
+ case PqReplMsg_PrimaryStatusRequest:
ProcessStandbyPSRequestMessage();
break;
@@ -2752,7 +2755,7 @@ ProcessStandbyPSRequestMessage(void)
/* construct the message... */
resetStringInfo(&output_message);
- pq_sendbyte(&output_message, 's');
+ pq_sendbyte(&output_message, PqReplMsg_PrimaryStatusUpdate);
pq_sendint64(&output_message, lsn);
pq_sendint64(&output_message, (int64) U64FromFullTransactionId(fullOldestXidInCommit));
pq_sendint64(&output_message, (int64) U64FromFullTransactionId(nextFullXid));
@@ -3364,7 +3367,7 @@ XLogSendPhysical(void)
* OK to read and send the slice.
*/
resetStringInfo(&output_message);
- pq_sendbyte(&output_message, 'w');
+ pq_sendbyte(&output_message, PqReplMsg_WALData);
pq_sendint64(&output_message, startptr); /* dataStart */
pq_sendint64(&output_message, SendRqstPtr); /* walEnd */
@@ -4135,7 +4138,7 @@ WalSndKeepalive(bool requestReply, XLogRecPtr writePtr)
/* construct the message... */
resetStringInfo(&output_message);
- pq_sendbyte(&output_message, 'k');
+ pq_sendbyte(&output_message, PqReplMsg_Keepalive);
pq_sendint64(&output_message, XLogRecPtrIsInvalid(writePtr) ? sentPtr : writePtr);
pq_sendint64(&output_message, GetCurrentTimestamp());
pq_sendbyte(&output_message, requestReply ? 1 : 0);
diff --git a/src/backend/utils/activity/pgstat_shmem.c b/src/backend/utils/activity/pgstat_shmem.c
index 53e7d534270..cca4277f234 100644
--- a/src/backend/utils/activity/pgstat_shmem.c
+++ b/src/backend/utils/activity/pgstat_shmem.c
@@ -874,11 +874,12 @@ pgstat_drop_entry_internal(PgStatShared_HashEntry *shent,
*/
if (shent->dropped)
elog(ERROR,
- "trying to drop stats entry already dropped: kind=%s dboid=%u objid=%" PRIu64 " refcount=%u",
+ "trying to drop stats entry already dropped: kind=%s dboid=%u objid=%" PRIu64 " refcount=%u generation=%u",
pgstat_get_kind_info(shent->key.kind)->name,
shent->key.dboid,
shent->key.objid,
- pg_atomic_read_u32(&shent->refcount));
+ pg_atomic_read_u32(&shent->refcount),
+ pg_atomic_read_u32(&shent->generation));
shent->dropped = true;
/* release refcount marking entry as not dropped */
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index c9233565d57..122f2efab8b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -28,6 +28,7 @@
#include "common/hashfn.h"
#include "common/int.h"
+#include "common/int128.h"
#include "funcapi.h"
#include "lib/hyperloglog.h"
#include "libpq/pqformat.h"
@@ -534,10 +535,7 @@ static bool numericvar_to_int32(const NumericVar *var, int32 *result);
static bool numericvar_to_int64(const NumericVar *var, int64 *result);
static void int64_to_numericvar(int64 val, NumericVar *var);
static bool numericvar_to_uint64(const NumericVar *var, uint64 *result);
-#ifdef HAVE_INT128
-static bool numericvar_to_int128(const NumericVar *var, int128 *result);
-static void int128_to_numericvar(int128 val, NumericVar *var);
-#endif
+static void int128_to_numericvar(INT128 val, NumericVar *var);
static double numericvar_to_double_no_overflow(const NumericVar *var);
static Datum numeric_abbrev_convert(Datum original_datum, SortSupport ssup);
@@ -4463,25 +4461,13 @@ int64_div_fast_to_numeric(int64 val1, int log10val2)
if (unlikely(pg_mul_s64_overflow(val1, factor, &new_val1)))
{
-#ifdef HAVE_INT128
/* do the multiplication using 128-bit integers */
- int128 tmp;
+ INT128 tmp;
- tmp = (int128) val1 * (int128) factor;
+ tmp = int64_to_int128(0);
+ int128_add_int64_mul_int64(&tmp, val1, factor);
int128_to_numericvar(tmp, &result);
-#else
- /* do the multiplication using numerics */
- NumericVar tmp;
-
- init_var(&tmp);
-
- int64_to_numericvar(val1, &result);
- int64_to_numericvar(factor, &tmp);
- mul_var(&result, &tmp, &result, 0);
-
- free_var(&tmp);
-#endif
}
else
int64_to_numericvar(new_val1, &result);
@@ -4901,8 +4887,8 @@ numeric_pg_lsn(PG_FUNCTION_ARGS)
* Actually, it's a pointer to a NumericAggState allocated in the aggregate
* context. The digit buffers for the NumericVars will be there too.
*
- * On platforms which support 128-bit integers some aggregates instead use a
- * 128-bit integer based transition datatype to speed up calculations.
+ * For integer inputs, some aggregates use special-purpose 64-bit or 128-bit
+ * integer based transition datatypes to speed up calculations.
*
* ----------------------------------------------------------------------
*/
@@ -5566,26 +5552,27 @@ numeric_accum_inv(PG_FUNCTION_ARGS)
/*
- * Integer data types in general use Numeric accumulators to share code
- * and avoid risk of overflow.
+ * Integer data types in general use Numeric accumulators to share code and
+ * avoid risk of overflow. However for performance reasons optimized
+ * special-purpose accumulator routines are used when possible:
*
- * However for performance reasons optimized special-purpose accumulator
- * routines are used when possible.
+ * For 16-bit and 32-bit inputs, N and sum(X) fit into 64-bit, so 64-bit
+ * accumulators are used for SUM and AVG of these data types.
*
- * On platforms with 128-bit integer support, the 128-bit routines will be
- * used when sum(X) or sum(X*X) fit into 128-bit.
+ * For 16-bit and 32-bit inputs, sum(X^2) fits into 128-bit, so 128-bit
+ * accumulators are used for STDDEV_POP, STDDEV_SAMP, VAR_POP, and VAR_SAMP of
+ * these data types.
*
- * For 16 and 32 bit inputs, the N and sum(X) fit into 64-bit so the 64-bit
- * accumulators will be used for SUM and AVG of these data types.
+ * For 64-bit inputs, sum(X) fits into 128-bit, so a 128-bit accumulator is
+ * used for SUM(int8) and AVG(int8).
*/
-#ifdef HAVE_INT128
typedef struct Int128AggState
{
bool calcSumX2; /* if true, calculate sumX2 */
int64 N; /* count of processed numbers */
- int128 sumX; /* sum of processed numbers */
- int128 sumX2; /* sum of squares of processed numbers */
+ INT128 sumX; /* sum of processed numbers */
+ INT128 sumX2; /* sum of squares of processed numbers */
} Int128AggState;
/*
@@ -5631,12 +5618,12 @@ makeInt128AggStateCurrentContext(bool calcSumX2)
* Accumulate a new input value for 128-bit aggregate functions.
*/
static void
-do_int128_accum(Int128AggState *state, int128 newval)
+do_int128_accum(Int128AggState *state, int64 newval)
{
if (state->calcSumX2)
- state->sumX2 += newval * newval;
+ int128_add_int64_mul_int64(&state->sumX2, newval, newval);
- state->sumX += newval;
+ int128_add_int64(&state->sumX, newval);
state->N++;
}
@@ -5644,43 +5631,28 @@ do_int128_accum(Int128AggState *state, int128 newval)
* Remove an input value from the aggregated state.
*/
static void
-do_int128_discard(Int128AggState *state, int128 newval)
+do_int128_discard(Int128AggState *state, int64 newval)
{
if (state->calcSumX2)
- state->sumX2 -= newval * newval;
+ int128_sub_int64_mul_int64(&state->sumX2, newval, newval);
- state->sumX -= newval;
+ int128_sub_int64(&state->sumX, newval);
state->N--;
}
-typedef Int128AggState PolyNumAggState;
-#define makePolyNumAggState makeInt128AggState
-#define makePolyNumAggStateCurrentContext makeInt128AggStateCurrentContext
-#else
-typedef NumericAggState PolyNumAggState;
-#define makePolyNumAggState makeNumericAggState
-#define makePolyNumAggStateCurrentContext makeNumericAggStateCurrentContext
-#endif
-
Datum
int2_accum(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makePolyNumAggState(fcinfo, true);
+ state = makeInt128AggState(fcinfo, true);
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_accum(state, (int128) PG_GETARG_INT16(1));
-#else
- do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT16(1)));
-#endif
- }
+ do_int128_accum(state, PG_GETARG_INT16(1));
PG_RETURN_POINTER(state);
}
@@ -5688,22 +5660,16 @@ int2_accum(PG_FUNCTION_ARGS)
Datum
int4_accum(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makePolyNumAggState(fcinfo, true);
+ state = makeInt128AggState(fcinfo, true);
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_accum(state, (int128) PG_GETARG_INT32(1));
-#else
- do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT32(1)));
-#endif
- }
+ do_int128_accum(state, PG_GETARG_INT32(1));
PG_RETURN_POINTER(state);
}
@@ -5726,21 +5692,21 @@ int8_accum(PG_FUNCTION_ARGS)
}
/*
- * Combine function for numeric aggregates which require sumX2
+ * Combine function for Int128AggState for aggregates which require sumX2
*/
Datum
numeric_poly_combine(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state1;
- PolyNumAggState *state2;
+ Int128AggState *state1;
+ Int128AggState *state2;
MemoryContext agg_context;
MemoryContext old_context;
if (!AggCheckCallContext(fcinfo, &agg_context))
elog(ERROR, "aggregate function called in non-aggregate context");
- state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
- state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
+ state1 = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+ state2 = PG_ARGISNULL(1) ? NULL : (Int128AggState *) PG_GETARG_POINTER(1);
if (state2 == NULL)
PG_RETURN_POINTER(state1);
@@ -5750,16 +5716,10 @@ numeric_poly_combine(PG_FUNCTION_ARGS)
{
old_context = MemoryContextSwitchTo(agg_context);
- state1 = makePolyNumAggState(fcinfo, true);
+ state1 = makeInt128AggState(fcinfo, true);
state1->N = state2->N;
-
-#ifdef HAVE_INT128
state1->sumX = state2->sumX;
state1->sumX2 = state2->sumX2;
-#else
- accum_sum_copy(&state1->sumX, &state2->sumX);
- accum_sum_copy(&state1->sumX2, &state2->sumX2);
-#endif
MemoryContextSwitchTo(old_context);
@@ -5769,54 +5729,51 @@ numeric_poly_combine(PG_FUNCTION_ARGS)
if (state2->N > 0)
{
state1->N += state2->N;
+ int128_add_int128(&state1->sumX, state2->sumX);
+ int128_add_int128(&state1->sumX2, state2->sumX2);
+ }
+ PG_RETURN_POINTER(state1);
+}
-#ifdef HAVE_INT128
- state1->sumX += state2->sumX;
- state1->sumX2 += state2->sumX2;
-#else
- /* The rest of this needs to work in the aggregate context */
- old_context = MemoryContextSwitchTo(agg_context);
-
- /* Accumulate sums */
- accum_sum_combine(&state1->sumX, &state2->sumX);
- accum_sum_combine(&state1->sumX2, &state2->sumX2);
+/*
+ * int128_serialize - serialize a 128-bit integer to binary format
+ */
+static inline void
+int128_serialize(StringInfo buf, INT128 val)
+{
+ pq_sendint64(buf, PG_INT128_HI_INT64(val));
+ pq_sendint64(buf, PG_INT128_LO_UINT64(val));
+}
- MemoryContextSwitchTo(old_context);
-#endif
+/*
+ * int128_deserialize - deserialize binary format to a 128-bit integer.
+ */
+static inline INT128
+int128_deserialize(StringInfo buf)
+{
+ int64 hi = pq_getmsgint64(buf);
+ uint64 lo = pq_getmsgint64(buf);
- }
- PG_RETURN_POINTER(state1);
+ return make_int128(hi, lo);
}
/*
* numeric_poly_serialize
- * Serialize PolyNumAggState into bytea for aggregate functions which
+ * Serialize Int128AggState into bytea for aggregate functions which
* require sumX2.
*/
Datum
numeric_poly_serialize(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
StringInfoData buf;
bytea *result;
- NumericVar tmp_var;
/* Ensure we disallow calling when not in aggregate context */
if (!AggCheckCallContext(fcinfo, NULL))
elog(ERROR, "aggregate function called in non-aggregate context");
- state = (PolyNumAggState *) PG_GETARG_POINTER(0);
-
- /*
- * If the platform supports int128 then sumX and sumX2 will be a 128 bit
- * integer type. Here we'll convert that into a numeric type so that the
- * combine state is in the same format for both int128 enabled machines
- * and machines which don't support that type. The logic here is that one
- * day we might like to send these over to another server for further
- * processing and we want a standard format to work with.
- */
-
- init_var(&tmp_var);
+ state = (Int128AggState *) PG_GETARG_POINTER(0);
pq_begintypsend(&buf);
@@ -5824,48 +5781,33 @@ numeric_poly_serialize(PG_FUNCTION_ARGS)
pq_sendint64(&buf, state->N);
/* sumX */
-#ifdef HAVE_INT128
- int128_to_numericvar(state->sumX, &tmp_var);
-#else
- accum_sum_final(&state->sumX, &tmp_var);
-#endif
- numericvar_serialize(&buf, &tmp_var);
+ int128_serialize(&buf, state->sumX);
/* sumX2 */
-#ifdef HAVE_INT128
- int128_to_numericvar(state->sumX2, &tmp_var);
-#else
- accum_sum_final(&state->sumX2, &tmp_var);
-#endif
- numericvar_serialize(&buf, &tmp_var);
+ int128_serialize(&buf, state->sumX2);
result = pq_endtypsend(&buf);
- free_var(&tmp_var);
-
PG_RETURN_BYTEA_P(result);
}
/*
* numeric_poly_deserialize
- * Deserialize PolyNumAggState from bytea for aggregate functions which
+ * Deserialize Int128AggState from bytea for aggregate functions which
* require sumX2.
*/
Datum
numeric_poly_deserialize(PG_FUNCTION_ARGS)
{
bytea *sstate;
- PolyNumAggState *result;
+ Int128AggState *result;
StringInfoData buf;
- NumericVar tmp_var;
if (!AggCheckCallContext(fcinfo, NULL))
elog(ERROR, "aggregate function called in non-aggregate context");
sstate = PG_GETARG_BYTEA_PP(0);
- init_var(&tmp_var);
-
/*
* Initialize a StringInfo so that we can "receive" it using the standard
* recv-function infrastructure.
@@ -5873,31 +5815,19 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
VARSIZE_ANY_EXHDR(sstate));
- result = makePolyNumAggStateCurrentContext(false);
+ result = makeInt128AggStateCurrentContext(false);
/* N */
result->N = pq_getmsgint64(&buf);
/* sumX */
- numericvar_deserialize(&buf, &tmp_var);
-#ifdef HAVE_INT128
- numericvar_to_int128(&tmp_var, &result->sumX);
-#else
- accum_sum_add(&result->sumX, &tmp_var);
-#endif
+ result->sumX = int128_deserialize(&buf);
/* sumX2 */
- numericvar_deserialize(&buf, &tmp_var);
-#ifdef HAVE_INT128
- numericvar_to_int128(&tmp_var, &result->sumX2);
-#else
- accum_sum_add(&result->sumX2, &tmp_var);
-#endif
+ result->sumX2 = int128_deserialize(&buf);
pq_getmsgend(&buf);
- free_var(&tmp_var);
-
PG_RETURN_POINTER(result);
}
@@ -5907,43 +5837,37 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
Datum
int8_avg_accum(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Create the state data on the first call */
if (state == NULL)
- state = makePolyNumAggState(fcinfo, false);
+ state = makeInt128AggState(fcinfo, false);
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_accum(state, (int128) PG_GETARG_INT64(1));
-#else
- do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT64(1)));
-#endif
- }
+ do_int128_accum(state, PG_GETARG_INT64(1));
PG_RETURN_POINTER(state);
}
/*
- * Combine function for PolyNumAggState for aggregates which don't require
+ * Combine function for Int128AggState for aggregates which don't require
* sumX2
*/
Datum
int8_avg_combine(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state1;
- PolyNumAggState *state2;
+ Int128AggState *state1;
+ Int128AggState *state2;
MemoryContext agg_context;
MemoryContext old_context;
if (!AggCheckCallContext(fcinfo, &agg_context))
elog(ERROR, "aggregate function called in non-aggregate context");
- state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
- state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
+ state1 = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
+ state2 = PG_ARGISNULL(1) ? NULL : (Int128AggState *) PG_GETARG_POINTER(1);
if (state2 == NULL)
PG_RETURN_POINTER(state1);
@@ -5953,14 +5877,10 @@ int8_avg_combine(PG_FUNCTION_ARGS)
{
old_context = MemoryContextSwitchTo(agg_context);
- state1 = makePolyNumAggState(fcinfo, false);
+ state1 = makeInt128AggState(fcinfo, false);
state1->N = state2->N;
-
-#ifdef HAVE_INT128
state1->sumX = state2->sumX;
-#else
- accum_sum_copy(&state1->sumX, &state2->sumX);
-#endif
+
MemoryContextSwitchTo(old_context);
PG_RETURN_POINTER(state1);
@@ -5969,52 +5889,28 @@ int8_avg_combine(PG_FUNCTION_ARGS)
if (state2->N > 0)
{
state1->N += state2->N;
-
-#ifdef HAVE_INT128
- state1->sumX += state2->sumX;
-#else
- /* The rest of this needs to work in the aggregate context */
- old_context = MemoryContextSwitchTo(agg_context);
-
- /* Accumulate sums */
- accum_sum_combine(&state1->sumX, &state2->sumX);
-
- MemoryContextSwitchTo(old_context);
-#endif
-
+ int128_add_int128(&state1->sumX, state2->sumX);
}
PG_RETURN_POINTER(state1);
}
/*
* int8_avg_serialize
- * Serialize PolyNumAggState into bytea using the standard
- * recv-function infrastructure.
+ * Serialize Int128AggState into bytea for aggregate functions which
+ * don't require sumX2.
*/
Datum
int8_avg_serialize(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
StringInfoData buf;
bytea *result;
- NumericVar tmp_var;
/* Ensure we disallow calling when not in aggregate context */
if (!AggCheckCallContext(fcinfo, NULL))
elog(ERROR, "aggregate function called in non-aggregate context");
- state = (PolyNumAggState *) PG_GETARG_POINTER(0);
-
- /*
- * If the platform supports int128 then sumX will be a 128 integer type.
- * Here we'll convert that into a numeric type so that the combine state
- * is in the same format for both int128 enabled machines and machines
- * which don't support that type. The logic here is that one day we might
- * like to send these over to another server for further processing and we
- * want a standard format to work with.
- */
-
- init_var(&tmp_var);
+ state = (Int128AggState *) PG_GETARG_POINTER(0);
pq_begintypsend(&buf);
@@ -6022,39 +5918,30 @@ int8_avg_serialize(PG_FUNCTION_ARGS)
pq_sendint64(&buf, state->N);
/* sumX */
-#ifdef HAVE_INT128
- int128_to_numericvar(state->sumX, &tmp_var);
-#else
- accum_sum_final(&state->sumX, &tmp_var);
-#endif
- numericvar_serialize(&buf, &tmp_var);
+ int128_serialize(&buf, state->sumX);
result = pq_endtypsend(&buf);
- free_var(&tmp_var);
-
PG_RETURN_BYTEA_P(result);
}
/*
* int8_avg_deserialize
- * Deserialize bytea back into PolyNumAggState.
+ * Deserialize Int128AggState from bytea for aggregate functions which
+ * don't require sumX2.
*/
Datum
int8_avg_deserialize(PG_FUNCTION_ARGS)
{
bytea *sstate;
- PolyNumAggState *result;
+ Int128AggState *result;
StringInfoData buf;
- NumericVar tmp_var;
if (!AggCheckCallContext(fcinfo, NULL))
elog(ERROR, "aggregate function called in non-aggregate context");
sstate = PG_GETARG_BYTEA_PP(0);
- init_var(&tmp_var);
-
/*
* Initialize a StringInfo so that we can "receive" it using the standard
* recv-function infrastructure.
@@ -6062,23 +5949,16 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
VARSIZE_ANY_EXHDR(sstate));
- result = makePolyNumAggStateCurrentContext(false);
+ result = makeInt128AggStateCurrentContext(false);
/* N */
result->N = pq_getmsgint64(&buf);
/* sumX */
- numericvar_deserialize(&buf, &tmp_var);
-#ifdef HAVE_INT128
- numericvar_to_int128(&tmp_var, &result->sumX);
-#else
- accum_sum_add(&result->sumX, &tmp_var);
-#endif
+ result->sumX = int128_deserialize(&buf);
pq_getmsgend(&buf);
- free_var(&tmp_var);
-
PG_RETURN_POINTER(result);
}
@@ -6089,24 +5969,16 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
Datum
int2_accum_inv(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
elog(ERROR, "int2_accum_inv called with NULL state");
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_discard(state, (int128) PG_GETARG_INT16(1));
-#else
- /* Should never fail, all inputs have dscale 0 */
- if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT16(1))))
- elog(ERROR, "do_numeric_discard failed unexpectedly");
-#endif
- }
+ do_int128_discard(state, PG_GETARG_INT16(1));
PG_RETURN_POINTER(state);
}
@@ -6114,24 +5986,16 @@ int2_accum_inv(PG_FUNCTION_ARGS)
Datum
int4_accum_inv(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
elog(ERROR, "int4_accum_inv called with NULL state");
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_discard(state, (int128) PG_GETARG_INT32(1));
-#else
- /* Should never fail, all inputs have dscale 0 */
- if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT32(1))))
- elog(ERROR, "do_numeric_discard failed unexpectedly");
-#endif
- }
+ do_int128_discard(state, PG_GETARG_INT32(1));
PG_RETURN_POINTER(state);
}
@@ -6160,24 +6024,16 @@ int8_accum_inv(PG_FUNCTION_ARGS)
Datum
int8_avg_accum_inv(PG_FUNCTION_ARGS)
{
- PolyNumAggState *state;
+ Int128AggState *state;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* Should not get here with no state */
if (state == NULL)
elog(ERROR, "int8_avg_accum_inv called with NULL state");
if (!PG_ARGISNULL(1))
- {
-#ifdef HAVE_INT128
- do_int128_discard(state, (int128) PG_GETARG_INT64(1));
-#else
- /* Should never fail, all inputs have dscale 0 */
- if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT64(1))))
- elog(ERROR, "do_numeric_discard failed unexpectedly");
-#endif
- }
+ do_int128_discard(state, PG_GETARG_INT64(1));
PG_RETURN_POINTER(state);
}
@@ -6185,12 +6041,11 @@ int8_avg_accum_inv(PG_FUNCTION_ARGS)
Datum
numeric_poly_sum(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
Numeric res;
NumericVar result;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* If there were no non-null inputs, return NULL */
if (state == NULL || state->N == 0)
@@ -6205,21 +6060,17 @@ numeric_poly_sum(PG_FUNCTION_ARGS)
free_var(&result);
PG_RETURN_NUMERIC(res);
-#else
- return numeric_sum(fcinfo);
-#endif
}
Datum
numeric_poly_avg(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
NumericVar result;
Datum countd,
sumd;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
/* If there were no non-null inputs, return NULL */
if (state == NULL || state->N == 0)
@@ -6235,9 +6086,6 @@ numeric_poly_avg(PG_FUNCTION_ARGS)
free_var(&result);
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
-#else
- return numeric_avg(fcinfo);
-#endif
}
Datum
@@ -6470,7 +6318,6 @@ numeric_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NUMERIC(res);
}
-#ifdef HAVE_INT128
static Numeric
numeric_poly_stddev_internal(Int128AggState *state,
bool variance, bool sample,
@@ -6514,17 +6361,15 @@ numeric_poly_stddev_internal(Int128AggState *state,
return res;
}
-#endif
Datum
numeric_poly_var_samp(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
Numeric res;
bool is_null;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
res = numeric_poly_stddev_internal(state, true, true, &is_null);
@@ -6532,20 +6377,16 @@ numeric_poly_var_samp(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
-#else
- return numeric_var_samp(fcinfo);
-#endif
}
Datum
numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
Numeric res;
bool is_null;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
res = numeric_poly_stddev_internal(state, false, true, &is_null);
@@ -6553,20 +6394,16 @@ numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
-#else
- return numeric_stddev_samp(fcinfo);
-#endif
}
Datum
numeric_poly_var_pop(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
Numeric res;
bool is_null;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
res = numeric_poly_stddev_internal(state, true, false, &is_null);
@@ -6574,20 +6411,16 @@ numeric_poly_var_pop(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
-#else
- return numeric_var_pop(fcinfo);
-#endif
}
Datum
numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
{
-#ifdef HAVE_INT128
- PolyNumAggState *state;
+ Int128AggState *state;
Numeric res;
bool is_null;
- state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
+ state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
res = numeric_poly_stddev_internal(state, false, false, &is_null);
@@ -6595,9 +6428,6 @@ numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
-#else
- return numeric_stddev_pop(fcinfo);
-#endif
}
/*
@@ -8330,105 +8160,23 @@ numericvar_to_uint64(const NumericVar *var, uint64 *result)
return true;
}
-#ifdef HAVE_INT128
-/*
- * Convert numeric to int128, rounding if needed.
- *
- * If overflow, return false (no error is raised). Return true if okay.
- */
-static bool
-numericvar_to_int128(const NumericVar *var, int128 *result)
-{
- NumericDigit *digits;
- int ndigits;
- int weight;
- int i;
- int128 val,
- oldval;
- bool neg;
- NumericVar rounded;
-
- /* Round to nearest integer */
- init_var(&rounded);
- set_var_from_var(var, &rounded);
- round_var(&rounded, 0);
-
- /* Check for zero input */
- strip_var(&rounded);
- ndigits = rounded.ndigits;
- if (ndigits == 0)
- {
- *result = 0;
- free_var(&rounded);
- return true;
- }
-
- /*
- * For input like 10000000000, we must treat stripped digits as real. So
- * the loop assumes there are weight+1 digits before the decimal point.
- */
- weight = rounded.weight;
- Assert(weight >= 0 && ndigits <= weight + 1);
-
- /* Construct the result */
- digits = rounded.digits;
- neg = (rounded.sign == NUMERIC_NEG);
- val = digits[0];
- for (i = 1; i <= weight; i++)
- {
- oldval = val;
- val *= NBASE;
- if (i < ndigits)
- val += digits[i];
-
- /*
- * The overflow check is a bit tricky because we want to accept
- * INT128_MIN, which will overflow the positive accumulator. We can
- * detect this case easily though because INT128_MIN is the only
- * nonzero value for which -val == val (on a two's complement machine,
- * anyway).
- */
- if ((val / NBASE) != oldval) /* possible overflow? */
- {
- if (!neg || (-val) != val || val == 0 || oldval < 0)
- {
- free_var(&rounded);
- return false;
- }
- }
- }
-
- free_var(&rounded);
-
- *result = neg ? -val : val;
- return true;
-}
-
/*
* Convert 128 bit integer to numeric.
*/
static void
-int128_to_numericvar(int128 val, NumericVar *var)
+int128_to_numericvar(INT128 val, NumericVar *var)
{
- uint128 uval,
- newuval;
+ int sign;
NumericDigit *ptr;
int ndigits;
+ int32 dig;
/* int128 can require at most 39 decimal digits; add one for safety */
alloc_var(var, 40 / DEC_DIGITS);
- if (val < 0)
- {
- var->sign = NUMERIC_NEG;
- uval = -val;
- }
- else
- {
- var->sign = NUMERIC_POS;
- uval = val;
- }
+ sign = int128_sign(val);
+ var->sign = sign < 0 ? NUMERIC_NEG : NUMERIC_POS;
var->dscale = 0;
- if (val == 0)
+ if (sign == 0)
{
var->ndigits = 0;
var->weight = 0;
@@ -8440,15 +8188,13 @@ int128_to_numericvar(int128 val, NumericVar *var)
{
ptr--;
ndigits++;
- newuval = uval / NBASE;
- *ptr = uval - newuval * NBASE;
- uval = newuval;
- } while (uval);
+ int128_div_mod_int32(&val, NBASE, &dig);
+ *ptr = (NumericDigit) abs(dig);
+ } while (!int128_is_zero(val));
var->digits = ptr;
var->ndigits = ndigits;
var->weight = ndigits - 1;
}
-#endif
/*
* Convert a NumericVar to float8; if out of range, return +/- HUGE_VAL
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 25cff56c3d0..e640b48205b 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -4954,7 +4954,7 @@ timestamptz_trunc_internal(text *units, TimestampTz timestamp, pg_tz *tzp)
case DTK_SECOND:
case DTK_MILLISEC:
case DTK_MICROSEC:
- PG_RETURN_TIMESTAMPTZ(timestamp);
+ return timestamp;
break;
default:
diff --git a/src/bin/pg_basebackup/pg_basebackup.c b/src/bin/pg_basebackup/pg_basebackup.c
index 55621f35fb6..0a3ca4315de 100644
--- a/src/bin/pg_basebackup/pg_basebackup.c
+++ b/src/bin/pg_basebackup/pg_basebackup.c
@@ -35,6 +35,7 @@
#include "fe_utils/option_utils.h"
#include "fe_utils/recovery_gen.h"
#include "getopt_long.h"
+#include "libpq/protocol.h"
#include "receivelog.h"
#include "streamutil.h"
@@ -1338,7 +1339,7 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
/* Each CopyData message begins with a type byte. */
switch (GetCopyDataByte(r, copybuf, &cursor))
{
- case 'n':
+ case PqBackupMsg_NewArchive:
{
/* New archive. */
char *archive_name;
@@ -1410,7 +1411,7 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
break;
}
- case 'd':
+ case PqMsg_CopyData:
{
/* Archive or manifest data. */
if (state->manifest_buffer != NULL)
@@ -1446,7 +1447,7 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
break;
}
- case 'p':
+ case PqBackupMsg_ProgressReport:
{
/*
* Progress report.
@@ -1465,7 +1466,7 @@ ReceiveArchiveStreamChunk(size_t r, char *copybuf, void *callback_data)
break;
}
- case 'm':
+ case PqBackupMsg_Manifest:
{
/*
* Manifest data will be sent next. This message is not
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 0e9d2e23947..7a4d1a2d2ca 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -24,6 +24,7 @@
#include "getopt_long.h"
#include "libpq-fe.h"
#include "libpq/pqsignal.h"
+#include "libpq/protocol.h"
#include "pqexpbuffer.h"
#include "streamutil.h"
@@ -149,7 +150,7 @@ sendFeedback(PGconn *conn, TimestampTz now, bool force, bool replyRequested)
LSN_FORMAT_ARGS(output_fsync_lsn),
replication_slot);
- replybuf[len] = 'r';
+ replybuf[len] = PqReplMsg_StandbyStatusUpdate;
len += 1;
fe_sendint64(output_written_lsn, &replybuf[len]); /* write */
len += 8;
@@ -454,7 +455,7 @@ StreamLogicalLog(void)
}
/* Check the message type. */
- if (copybuf[0] == 'k')
+ if (copybuf[0] == PqReplMsg_Keepalive)
{
int pos;
bool replyRequested;
@@ -466,7 +467,7 @@ StreamLogicalLog(void)
* We just check if the server requested a reply, and ignore the
* rest.
*/
- pos = 1; /* skip msgtype 'k' */
+ pos = 1; /* skip msgtype PqReplMsg_Keepalive */
walEnd = fe_recvint64(&copybuf[pos]);
output_written_lsn = Max(walEnd, output_written_lsn);
@@ -509,7 +510,7 @@ StreamLogicalLog(void)
continue;
}
- else if (copybuf[0] != 'w')
+ else if (copybuf[0] != PqReplMsg_WALData)
{
pg_log_error("unrecognized streaming header: \"%c\"",
copybuf[0]);
@@ -521,7 +522,7 @@ StreamLogicalLog(void)
* message. We only need the WAL location field (dataStart), the rest
* of the header is ignored.
*/
- hdr_len = 1; /* msgtype 'w' */
+ hdr_len = 1; /* msgtype PqReplMsg_WALData */
hdr_len += 8; /* dataStart */
hdr_len += 8; /* walEnd */
hdr_len += 8; /* sendTime */
diff --git a/src/bin/pg_basebackup/receivelog.c b/src/bin/pg_basebackup/receivelog.c
index f2b54d3c501..25b13c7f55c 100644
--- a/src/bin/pg_basebackup/receivelog.c
+++ b/src/bin/pg_basebackup/receivelog.c
@@ -21,6 +21,7 @@
#include "access/xlog_internal.h"
#include "common/logging.h"
#include "libpq-fe.h"
+#include "libpq/protocol.h"
#include "receivelog.h"
#include "streamutil.h"
@@ -338,7 +339,7 @@ sendFeedback(PGconn *conn, XLogRecPtr blockpos, TimestampTz now, bool replyReque
char replybuf[1 + 8 + 8 + 8 + 8 + 1];
int len = 0;
- replybuf[len] = 'r';
+ replybuf[len] = PqReplMsg_StandbyStatusUpdate;
len += 1;
fe_sendint64(blockpos, &replybuf[len]); /* write */
len += 8;
@@ -823,13 +824,13 @@ HandleCopyStream(PGconn *conn, StreamCtl *stream,
}
/* Check the message type. */
- if (copybuf[0] == 'k')
+ if (copybuf[0] == PqReplMsg_Keepalive)
{
if (!ProcessKeepaliveMsg(conn, stream, copybuf, r, blockpos,
&last_status))
goto error;
}
- else if (copybuf[0] == 'w')
+ else if (copybuf[0] == PqReplMsg_WALData)
{
if (!ProcessWALDataMsg(conn, stream, copybuf, r, &blockpos))
goto error;
@@ -1001,7 +1002,7 @@ ProcessKeepaliveMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
* Parse the keepalive message, enclosed in the CopyData message. We just
* check if the server requested a reply, and ignore the rest.
*/
- pos = 1; /* skip msgtype 'k' */
+ pos = 1; /* skip msgtype PqReplMsg_Keepalive */
pos += 8; /* skip walEnd */
pos += 8; /* skip sendTime */
@@ -1064,7 +1065,7 @@ ProcessWALDataMsg(PGconn *conn, StreamCtl *stream, char *copybuf, int len,
* message. We only need the WAL location field (dataStart), the rest of
* the header is ignored.
*/
- hdr_len = 1; /* msgtype 'w' */
+ hdr_len = 1; /* msgtype PqReplMsg_WALData */
hdr_len += 8; /* dataStart */
hdr_len += 8; /* walEnd */
hdr_len += 8; /* sendTime */
diff --git a/src/bin/pg_upgrade/check.c b/src/bin/pg_upgrade/check.c
index 310f53c5577..67eedbae265 100644
--- a/src/bin/pg_upgrade/check.c
+++ b/src/bin/pg_upgrade/check.c
@@ -1713,7 +1713,7 @@ check_for_not_null_inheritance(ClusterInfo *cluster)
"If the parent column(s) are NOT NULL, then the child column must\n"
"also be marked NOT NULL, or the upgrade will fail.\n"
"You can fix this by running\n"
- " ALTER TABLE tablename ALTER column SET NOT NULL;\n"
+ " ALTER TABLE tablename ALTER column SET NOT NULL;\n"
"on each column listed in the file:\n"
" %s", report.path);
}
diff --git a/src/include/common/int128.h b/src/include/common/int128.h
index 8c300e56d9a..62aae1bc6a7 100644
--- a/src/include/common/int128.h
+++ b/src/include/common/int128.h
@@ -37,11 +37,18 @@
* that a native int128 type would (probably) have. This makes no difference
* for ordinary use of INT128, but allows union'ing INT128 with int128 for
* testing purposes.
+ *
+ * PG_INT128_HI_INT64 and PG_INT128_LO_UINT64 allow the (signed) high and
+ * (unsigned) low 64-bit integer parts to be extracted portably on all
+ * platforms.
*/
#if USE_NATIVE_INT128
typedef int128 INT128;
+#define PG_INT128_HI_INT64(i128) ((int64) ((i128) >> 64))
+#define PG_INT128_LO_UINT64(i128) ((uint64) (i128))
+
#else
typedef struct
@@ -55,7 +62,28 @@ typedef struct
#endif
} INT128;
+#define PG_INT128_HI_INT64(i128) ((i128).hi)
+#define PG_INT128_LO_UINT64(i128) ((i128).lo)
+
+#endif
+
+/*
+ * Construct an INT128 from (signed) high and (unsigned) low 64-bit integer
+ * parts.
+ */
+static inline INT128
+make_int128(int64 hi, uint64 lo)
+{
+#if USE_NATIVE_INT128
+ return (((int128) hi) << 64) + lo;
+#else
+ INT128 val;
+
+ val.hi = hi;
+ val.lo = lo;
+ return val;
#endif
+}
/*
* Add an unsigned int64 value into an INT128 variable.
@@ -68,17 +96,17 @@ int128_add_uint64(INT128 *i128, uint64 v)
#else
/*
* First add the value to the .lo part, then check to see if a carry needs
- * to be propagated into the .hi part. A carry is needed if both inputs
- * have high bits set, or if just one input has high bit set while the new
- * .lo part doesn't. Remember that .lo part is unsigned; we cast to
- * signed here just as a cheap way to check the high bit.
+ * to be propagated into the .hi part. Since this is unsigned integer
+ * arithmetic, which is just modular arithmetic, a carry is needed if the
+ * new .lo part is less than the old .lo part (i.e., if modular
+ * wrap-around occurred). Writing this in the form below, rather than
+ * using an "if" statement causes modern compilers to produce branchless
+ * machine code identical to the native code.
*/
uint64 oldlo = i128->lo;
i128->lo += v;
- if (((int64) v < 0 && (int64) oldlo < 0) ||
- (((int64) v < 0 || (int64) oldlo < 0) && (int64) i128->lo >= 0))
- i128->hi++;
+ i128->hi += (i128->lo < oldlo);
#endif
}
@@ -93,32 +121,80 @@ int128_add_int64(INT128 *i128, int64 v)
#else
/*
* This is much like the above except that the carry logic differs for
- * negative v. Ordinarily we'd need to subtract 1 from the .hi part
- * (corresponding to adding the sign-extended bits of v to it); but if
- * there is a carry out of the .lo part, that cancels and we do nothing.
+ * negative v -- we need to subtract 1 from the .hi part if the new .lo
+ * value is greater than the old .lo value. That can be achieved without
+ * any branching by adding the sign bit from v (v >> 63 = 0 or -1) to the
+ * previous result (for negative v, if the new .lo value is less than the
+ * old .lo value, the two terms cancel and we leave the .hi part
+ * unchanged, otherwise we subtract 1 from the .hi part). With modern
+ * compilers this often produces machine code identical to the native
+ * code.
*/
uint64 oldlo = i128->lo;
i128->lo += v;
- if (v >= 0)
- {
- if ((int64) oldlo < 0 && (int64) i128->lo >= 0)
- i128->hi++;
- }
- else
- {
- if (!((int64) oldlo < 0 || (int64) i128->lo >= 0))
- i128->hi--;
- }
+ i128->hi += (i128->lo < oldlo) + (v >> 63);
+#endif
+}
+
+/*
+ * Add an INT128 value into an INT128 variable.
+ */
+static inline void
+int128_add_int128(INT128 *i128, INT128 v)
+{
+#if USE_NATIVE_INT128
+ *i128 += v;
+#else
+ int128_add_uint64(i128, v.lo);
+ i128->hi += v.hi;
+#endif
+}
+
+/*
+ * Subtract an unsigned int64 value from an INT128 variable.
+ */
+static inline void
+int128_sub_uint64(INT128 *i128, uint64 v)
+{
+#if USE_NATIVE_INT128
+ *i128 -= v;
+#else
+ /*
+ * This is like int128_add_uint64(), except we must propagate a borrow to
+ * (subtract 1 from) the .hi part if the new .lo part is greater than the
+ * old .lo part.
+ */
+ uint64 oldlo = i128->lo;
+
+ i128->lo -= v;
+ i128->hi -= (i128->lo > oldlo);
+#endif
+}
+
+/*
+ * Subtract a signed int64 value from an INT128 variable.
+ */
+static inline void
+int128_sub_int64(INT128 *i128, int64 v)
+{
+#if USE_NATIVE_INT128
+ *i128 -= v;
+#else
+ /* Like int128_add_int64() with the sign of v inverted */
+ uint64 oldlo = i128->lo;
+
+ i128->lo -= v;
+ i128->hi -= (i128->lo > oldlo) + (v >> 63);
#endif
}
/*
- * INT64_AU32 extracts the most significant 32 bits of int64 as int64, while
- * INT64_AL32 extracts the least significant 32 bits as uint64.
+ * INT64_HI_INT32 extracts the most significant 32 bits of int64 as int32.
+ * INT64_LO_UINT32 extracts the least significant 32 bits as uint32.
*/
-#define INT64_AU32(i64) ((i64) >> 32)
-#define INT64_AL32(i64) ((i64) & UINT64CONST(0xFFFFFFFF))
+#define INT64_HI_INT32(i64) ((int32) ((i64) >> 32))
+#define INT64_LO_UINT32(i64) ((uint32) (i64))
/*
* Add the 128-bit product of two int64 values into an INT128 variable.
@@ -133,7 +209,7 @@ int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
*/
*i128 += (int128) x * (int128) y;
#else
- /* INT64_AU32 must use arithmetic right shift */
+ /* INT64_HI_INT32 must use arithmetic right shift */
StaticAssertDecl(((int64) -1 >> 1) == (int64) -1,
"arithmetic right shift is needed");
@@ -158,38 +234,191 @@ int128_add_int64_mul_int64(INT128 *i128, int64 x, int64 y)
/* No need to work hard if product must be zero */
if (x != 0 && y != 0)
{
- int64 x_u32 = INT64_AU32(x);
- uint64 x_l32 = INT64_AL32(x);
- int64 y_u32 = INT64_AU32(y);
- uint64 y_l32 = INT64_AL32(y);
+ int32 x_hi = INT64_HI_INT32(x);
+ uint32 x_lo = INT64_LO_UINT32(x);
+ int32 y_hi = INT64_HI_INT32(y);
+ uint32 y_lo = INT64_LO_UINT32(y);
int64 tmp;
/* the first term */
- i128->hi += x_u32 * y_u32;
-
- /* the second term: sign-extend it only if x is negative */
- tmp = x_u32 * y_l32;
- if (x < 0)
- i128->hi += INT64_AU32(tmp);
- else
- i128->hi += ((uint64) tmp) >> 32;
- int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32);
-
- /* the third term: sign-extend it only if y is negative */
- tmp = x_l32 * y_u32;
- if (y < 0)
- i128->hi += INT64_AU32(tmp);
- else
- i128->hi += ((uint64) tmp) >> 32;
- int128_add_uint64(i128, ((uint64) INT64_AL32(tmp)) << 32);
+ i128->hi += (int64) x_hi * (int64) y_hi;
+
+ /* the second term: sign-extended with the sign of x */
+ tmp = (int64) x_hi * (int64) y_lo;
+ i128->hi += INT64_HI_INT32(tmp);
+ int128_add_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
+
+ /* the third term: sign-extended with the sign of y */
+ tmp = (int64) x_lo * (int64) y_hi;
+ i128->hi += INT64_HI_INT32(tmp);
+ int128_add_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
/* the fourth term: always unsigned */
- int128_add_uint64(i128, x_l32 * y_l32);
+ int128_add_uint64(i128, (uint64) x_lo * (uint64) y_lo);
}
#endif
}
/*
+ * Subtract the 128-bit product of two int64 values from an INT128 variable.
+ */
+static inline void
+int128_sub_int64_mul_int64(INT128 *i128, int64 x, int64 y)
+{
+#if USE_NATIVE_INT128
+ *i128 -= (int128) x * (int128) y;
+#else
+ /* As above, except subtract the 128-bit product */
+ if (x != 0 && y != 0)
+ {
+ int32 x_hi = INT64_HI_INT32(x);
+ uint32 x_lo = INT64_LO_UINT32(x);
+ int32 y_hi = INT64_HI_INT32(y);
+ uint32 y_lo = INT64_LO_UINT32(y);
+ int64 tmp;
+
+ /* the first term */
+ i128->hi -= (int64) x_hi * (int64) y_hi;
+
+ /* the second term: sign-extended with the sign of x */
+ tmp = (int64) x_hi * (int64) y_lo;
+ i128->hi -= INT64_HI_INT32(tmp);
+ int128_sub_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
+
+ /* the third term: sign-extended with the sign of y */
+ tmp = (int64) x_lo * (int64) y_hi;
+ i128->hi -= INT64_HI_INT32(tmp);
+ int128_sub_uint64(i128, ((uint64) INT64_LO_UINT32(tmp)) << 32);
+
+ /* the fourth term: always unsigned */
+ int128_sub_uint64(i128, (uint64) x_lo * (uint64) y_lo);
+ }
+#endif
+}
+
+/*
+ * Divide an INT128 variable by a signed int32 value, returning the quotient
+ * and remainder. The remainder will have the same sign as *i128.
+ *
+ * Note: This provides no protection against dividing by 0, or dividing
+ * INT128_MIN by -1, which overflows. It is the caller's responsibility to
+ * guard against those.
+ */
+static inline void
+int128_div_mod_int32(INT128 *i128, int32 v, int32 *remainder)
+{
+#if USE_NATIVE_INT128
+ int128 old_i128 = *i128;
+
+ *i128 /= v;
+ *remainder = (int32) (old_i128 - *i128 * v);
+#else
+ /*
+ * To avoid any intermediate values overflowing (as happens if INT64_MIN
+ * is divided by -1), we first compute the quotient abs(*i128) / abs(v)
+ * using unsigned 64-bit arithmetic, and then fix the signs up at the end.
+ *
+ * The quotient is computed using the short division algorithm described
+ * in Knuth volume 2, section 4.3.1 exercise 16 (cf. div_var_int() in
+ * numeric.c). Since the absolute value of the divisor is known to be at
+ * most 2^31, the remainder carried from one digit to the next is at most
+ * 2^31 - 1, and so there is no danger of overflow when this is combined
+ * with the next digit (a 32-bit unsigned integer).
+ */
+ uint64 n_hi;
+ uint64 n_lo;
+ uint32 d;
+ uint64 q;
+ uint64 r;
+ uint64 tmp;
+
+ /* numerator: absolute value of *i128 */
+ if (i128->hi < 0)
+ {
+ n_hi = 0 - ((uint64) i128->hi);
+ n_lo = 0 - i128->lo;
+ if (n_lo != 0)
+ n_hi--;
+ }
+ else
+ {
+ n_hi = i128->hi;
+ n_lo = i128->lo;
+ }
+
+ /* denomimator: absolute value of v */
+ d = abs(v);
+
+ /* quotient and remainder of high 64 bits */
+ q = n_hi / d;
+ r = n_hi % d;
+ n_hi = q;
+
+ /* quotient and remainder of next 32 bits (upper half of n_lo) */
+ tmp = (r << 32) + (n_lo >> 32);
+ q = tmp / d;
+ r = tmp % d;
+
+ /* quotient and remainder of last 32 bits (lower half of n_lo) */
+ tmp = (r << 32) + (uint32) n_lo;
+ n_lo = q << 32;
+ q = tmp / d;
+ r = tmp % d;
+ n_lo += q;
+
+ /* final remainder should have the same sign as *i128 */
+ *remainder = i128->hi < 0 ? (int32) (0 - r) : (int32) r;
+
+ /* store the quotient in *i128, negating it if necessary */
+ if ((i128->hi < 0) != (v < 0))
+ {
+ n_hi = 0 - n_hi;
+ n_lo = 0 - n_lo;
+ if (n_lo != 0)
+ n_hi--;
+ }
+ i128->hi = (int64) n_hi;
+ i128->lo = n_lo;
+#endif
+}
+
+/*
+ * Test if an INT128 value is zero.
+ */
+static inline bool
+int128_is_zero(INT128 x)
+{
+#if USE_NATIVE_INT128
+ return x == 0;
+#else
+ return x.hi == 0 && x.lo == 0;
+#endif
+}
+
+/*
+ * Return the sign of an INT128 value (returns -1, 0, or +1).
+ */
+static inline int
+int128_sign(INT128 x)
+{
+#if USE_NATIVE_INT128
+ if (x < 0)
+ return -1;
+ if (x > 0)
+ return 1;
+ return 0;
+#else
+ if (x.hi < 0)
+ return -1;
+ if (x.hi > 0)
+ return 1;
+ if (x.lo > 0)
+ return 1;
+ return 0;
+#endif
+}
+
+/*
* Compare two INT128 values, return -1, 0, or +1.
*/
static inline int
diff --git a/src/include/libpq/protocol.h b/src/include/libpq/protocol.h
index b0bcb3cdc26..c64e628628d 100644
--- a/src/include/libpq/protocol.h
+++ b/src/include/libpq/protocol.h
@@ -69,6 +69,27 @@
#define PqMsg_Progress 'P'
+/* Replication codes sent by the primary (wrapped in CopyData messages). */
+
+#define PqReplMsg_Keepalive 'k'
+#define PqReplMsg_PrimaryStatusUpdate 's'
+#define PqReplMsg_WALData 'w'
+
+
+/* Replication codes sent by the standby (wrapped in CopyData messages). */
+
+#define PqReplMsg_HotStandbyFeedback 'h'
+#define PqReplMsg_PrimaryStatusRequest 'p'
+#define PqReplMsg_StandbyStatusUpdate 'r'
+
+
+/* Codes used for backups via COPY OUT (wrapped in CopyData messages). */
+
+#define PqBackupMsg_Manifest 'm'
+#define PqBackupMsg_NewArchive 'n'
+#define PqBackupMsg_ProgressReport 'p'
+
+
/* These are the authentication request codes sent by the backend. */
#define AUTH_REQ_OK 0 /* User is authenticated */
diff --git a/src/include/utils/pg_locale.h b/src/include/utils/pg_locale.h
index 931f5b3b880..2b072cafb4d 100644
--- a/src/include/utils/pg_locale.h
+++ b/src/include/utils/pg_locale.h
@@ -18,6 +18,8 @@
/* only include the C APIs, to avoid errors in cpluspluscheck */
#undef U_SHOW_CPLUSPLUS_API
#define U_SHOW_CPLUSPLUS_API 0
+#undef U_SHOW_CPLUSPLUS_HEADER_API
+#define U_SHOW_CPLUSPLUS_HEADER_API 0
#include <unicode/ucol.h>
#endif
diff --git a/src/test/modules/test_int128/test_int128.c b/src/test/modules/test_int128/test_int128.c
index caa06541a1f..c9c17a73a4e 100644
--- a/src/test/modules/test_int128/test_int128.c
+++ b/src/test/modules/test_int128/test_int128.c
@@ -93,8 +93,13 @@ main(int argc, char **argv)
int64 x = pg_prng_uint64(&pg_global_prng_state);
int64 y = pg_prng_uint64(&pg_global_prng_state);
int64 z = pg_prng_uint64(&pg_global_prng_state);
+ int64 w = pg_prng_uint64(&pg_global_prng_state);
+ int32 z32 = (int32) z;
test128 t1;
test128 t2;
+ test128 t3;
+ int32 r1;
+ int32 r2;
/* check unsigned addition */
t1.hl.hi = x;
@@ -126,25 +131,111 @@ main(int argc, char **argv)
return 1;
}
- /* check multiplication */
- t1.i128 = (int128) x * (int128) y;
+ /* check 128-bit signed addition */
+ t1.hl.hi = x;
+ t1.hl.lo = y;
+ t2 = t1;
+ t3.hl.hi = z;
+ t3.hl.lo = w;
+ t1.i128 += t3.i128;
+ int128_add_int128(&t2.I128, t3.I128);
- t2.hl.hi = t2.hl.lo = 0;
- int128_add_int64_mul_int64(&t2.I128, x, y);
+ if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
+ {
+ printf(INT128_HEX_FORMAT " + " INT128_HEX_FORMAT "\n", x, y, z, w);
+ printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+ printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
+ return 1;
+ }
+
+ /* check unsigned subtraction */
+ t1.hl.hi = x;
+ t1.hl.lo = y;
+ t2 = t1;
+ t1.i128 -= (int128) (uint64) z;
+ int128_sub_uint64(&t2.I128, (uint64) z);
if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
{
- printf("%016" PRIx64 " * %016" PRIx64 "\n", x, y);
+ printf(INT128_HEX_FORMAT " - unsigned %016" PRIx64 "\n", x, y, z);
printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
return 1;
}
+ /* check signed subtraction */
+ t1.hl.hi = x;
+ t1.hl.lo = y;
+ t2 = t1;
+ t1.i128 -= (int128) z;
+ int128_sub_int64(&t2.I128, z);
+
+ if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
+ {
+ printf(INT128_HEX_FORMAT " - signed %016" PRIx64 "\n", x, y, z);
+ printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+ printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
+ return 1;
+ }
+
+ /* check 64x64-bit multiply-add */
+ t1.hl.hi = x;
+ t1.hl.lo = y;
+ t2 = t1;
+ t1.i128 += (int128) z * (int128) w;
+ int128_add_int64_mul_int64(&t2.I128, z, w);
+
+ if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
+ {
+ printf(INT128_HEX_FORMAT " + %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
+ printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+ printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
+ return 1;
+ }
+
+ /* check 64x64-bit multiply-subtract */
+ t1.hl.hi = x;
+ t1.hl.lo = y;
+ t2 = t1;
+ t1.i128 -= (int128) z * (int128) w;
+ int128_sub_int64_mul_int64(&t2.I128, z, w);
+
+ if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
+ {
+ printf(INT128_HEX_FORMAT " - %016" PRIx64 " * %016" PRIx64 "\n", x, y, z, w);
+ printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+ printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
+ return 1;
+ }
+
+ /* check 128/32-bit division */
+ t3.hl.hi = x;
+ t3.hl.lo = y;
+ t1.i128 = t3.i128 / z32;
+ r1 = (int32) (t3.i128 % z32);
+ t2 = t3;
+ int128_div_mod_int32(&t2.I128, z32, &r2);
+
+ if (t1.hl.hi != t2.hl.hi || t1.hl.lo != t2.hl.lo)
+ {
+ printf(INT128_HEX_FORMAT " / signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
+ printf("native = " INT128_HEX_FORMAT "\n", t1.hl.hi, t1.hl.lo);
+ printf("result = " INT128_HEX_FORMAT "\n", t2.hl.hi, t2.hl.lo);
+ return 1;
+ }
+ if (r1 != r2)
+ {
+ printf(INT128_HEX_FORMAT " %% signed %08X\n", t3.hl.hi, t3.hl.lo, z32);
+ printf("native = %08X\n", r1);
+ printf("result = %08X\n", r2);
+ return 1;
+ }
+
/* check comparison */
t1.hl.hi = x;
t1.hl.lo = y;
t2.hl.hi = z;
- t2.hl.lo = pg_prng_uint64(&pg_global_prng_state);
+ t2.hl.lo = w;
if (my_int128_compare(t1.i128, t2.i128) !=
int128_compare(t1.I128, t2.I128))
diff --git a/src/test/regress/expected/aggregates.out b/src/test/regress/expected/aggregates.out
index 1f1ce2380af..7319945ffe3 100644
--- a/src/test/regress/expected/aggregates.out
+++ b/src/test/regress/expected/aggregates.out
@@ -680,6 +680,25 @@ SELECT sum2(q1,q2) FROM int8_tbl;
18271560493827981
(1 row)
+-- sanity checks
+SELECT sum(q1+q2), sum(q1)+sum(q2) FROM int8_tbl;
+ sum | ?column?
+-------------------+-------------------
+ 18271560493827981 | 18271560493827981
+(1 row)
+
+SELECT sum(q1-q2), sum(q2-q1), sum(q1)-sum(q2) FROM int8_tbl;
+ sum | sum | ?column?
+------------------+-------------------+------------------
+ 9135780246913245 | -9135780246913245 | 9135780246913245
+(1 row)
+
+SELECT sum(q1*2000), sum(-q1*2000), 2000*sum(q1) FROM int8_tbl;
+ sum | sum | ?column?
+----------------------+-----------------------+----------------------
+ 27407340740741226000 | -27407340740741226000 | 27407340740741226000
+(1 row)
+
-- test for outer-level aggregates
-- this should work
select ten, sum(distinct four) from onek a
diff --git a/src/test/regress/expected/timestamp.out b/src/test/regress/expected/timestamp.out
index 6aaa19c8f4e..14a9f5b56a6 100644
--- a/src/test/regress/expected/timestamp.out
+++ b/src/test/regress/expected/timestamp.out
@@ -591,6 +591,16 @@ SELECT date_trunc( 'week', timestamp '2004-02-29 15:44:17.71393' ) AS week_trunc
Mon Feb 23 00:00:00 2004
(1 row)
+SELECT date_trunc( 'week', timestamp 'infinity' ) AS inf_trunc;
+ inf_trunc
+-----------
+ infinity
+(1 row)
+
+SELECT date_trunc( 'timezone', timestamp '2004-02-29 15:44:17.71393' ) AS notsupp_trunc;
+ERROR: unit "timezone" not supported for type timestamp without time zone
+SELECT date_trunc( 'timezone', timestamp 'infinity' ) AS notsupp_inf_trunc;
+ERROR: unit "timezone" not supported for type timestamp without time zone
SELECT date_trunc( 'ago', timestamp 'infinity' ) AS invalid_trunc;
ERROR: unit "ago" not recognized for type timestamp without time zone
-- verify date_bin behaves the same as date_trunc for relevant intervals
diff --git a/src/test/regress/expected/timestamptz.out b/src/test/regress/expected/timestamptz.out
index 2a69953ff25..5dc8a621f6c 100644
--- a/src/test/regress/expected/timestamptz.out
+++ b/src/test/regress/expected/timestamptz.out
@@ -760,6 +760,16 @@ SELECT date_trunc( 'week', timestamp with time zone '2004-02-29 15:44:17.71393'
Mon Feb 23 00:00:00 2004 PST
(1 row)
+SELECT date_trunc( 'week', timestamp with time zone 'infinity' ) AS inf_trunc;
+ inf_trunc
+-----------
+ infinity
+(1 row)
+
+SELECT date_trunc( 'timezone', timestamp with time zone '2004-02-29 15:44:17.71393' ) AS notsupp_trunc;
+ERROR: unit "timezone" not supported for type timestamp with time zone
+SELECT date_trunc( 'timezone', timestamp with time zone 'infinity' ) AS notsupp_inf_trunc;
+ERROR: unit "timezone" not supported for type timestamp with time zone
SELECT date_trunc( 'ago', timestamp with time zone 'infinity' ) AS invalid_trunc;
ERROR: unit "ago" not recognized for type timestamp with time zone
SELECT date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'Australia/Sydney') as sydney_trunc; -- zone name
@@ -780,6 +790,14 @@ SELECT date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'VET
Thu Feb 15 20:00:00 2001 PST
(1 row)
+SELECT date_trunc('timezone', timestamp with time zone 'infinity', 'GMT') AS notsupp_zone_trunc;
+ERROR: unit "timezone" not supported for type timestamp with time zone
+SELECT date_trunc( 'week', timestamp with time zone 'infinity', 'GMT') AS inf_zone_trunc;
+ inf_zone_trunc
+----------------
+ infinity
+(1 row)
+
SELECT date_trunc('ago', timestamp with time zone 'infinity', 'GMT') AS invalid_zone_trunc;
ERROR: unit "ago" not recognized for type timestamp with time zone
-- verify date_bin behaves the same as date_trunc for relevant intervals
diff --git a/src/test/regress/sql/aggregates.sql b/src/test/regress/sql/aggregates.sql
index 277b4b198cc..dde85d0dfb2 100644
--- a/src/test/regress/sql/aggregates.sql
+++ b/src/test/regress/sql/aggregates.sql
@@ -182,6 +182,11 @@ SELECT newcnt(*) AS cnt_1000 FROM onek;
SELECT oldcnt(*) AS cnt_1000 FROM onek;
SELECT sum2(q1,q2) FROM int8_tbl;
+-- sanity checks
+SELECT sum(q1+q2), sum(q1)+sum(q2) FROM int8_tbl;
+SELECT sum(q1-q2), sum(q2-q1), sum(q1)-sum(q2) FROM int8_tbl;
+SELECT sum(q1*2000), sum(-q1*2000), 2000*sum(q1) FROM int8_tbl;
+
-- test for outer-level aggregates
-- this should work
diff --git a/src/test/regress/sql/timestamp.sql b/src/test/regress/sql/timestamp.sql
index 55f80530ea0..313757ed041 100644
--- a/src/test/regress/sql/timestamp.sql
+++ b/src/test/regress/sql/timestamp.sql
@@ -175,7 +175,9 @@ SELECT d1 - timestamp without time zone '1997-01-02' AS diff
FROM TIMESTAMP_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01';
SELECT date_trunc( 'week', timestamp '2004-02-29 15:44:17.71393' ) AS week_trunc;
-
+SELECT date_trunc( 'week', timestamp 'infinity' ) AS inf_trunc;
+SELECT date_trunc( 'timezone', timestamp '2004-02-29 15:44:17.71393' ) AS notsupp_trunc;
+SELECT date_trunc( 'timezone', timestamp 'infinity' ) AS notsupp_inf_trunc;
SELECT date_trunc( 'ago', timestamp 'infinity' ) AS invalid_trunc;
-- verify date_bin behaves the same as date_trunc for relevant intervals
diff --git a/src/test/regress/sql/timestamptz.sql b/src/test/regress/sql/timestamptz.sql
index caca3123f13..6ace851d169 100644
--- a/src/test/regress/sql/timestamptz.sql
+++ b/src/test/regress/sql/timestamptz.sql
@@ -217,15 +217,18 @@ SELECT d1 - timestamp with time zone '1997-01-02' AS diff
FROM TIMESTAMPTZ_TBL WHERE d1 BETWEEN '1902-01-01' AND '2038-01-01';
SELECT date_trunc( 'week', timestamp with time zone '2004-02-29 15:44:17.71393' ) AS week_trunc;
+SELECT date_trunc( 'week', timestamp with time zone 'infinity' ) AS inf_trunc;
+SELECT date_trunc( 'timezone', timestamp with time zone '2004-02-29 15:44:17.71393' ) AS notsupp_trunc;
+SELECT date_trunc( 'timezone', timestamp with time zone 'infinity' ) AS notsupp_inf_trunc;
SELECT date_trunc( 'ago', timestamp with time zone 'infinity' ) AS invalid_trunc;
SELECT date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'Australia/Sydney') as sydney_trunc; -- zone name
SELECT date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'GMT') as gmt_trunc; -- fixed-offset abbreviation
SELECT date_trunc('day', timestamp with time zone '2001-02-16 20:38:40+00', 'VET') as vet_trunc; -- variable-offset abbreviation
+SELECT date_trunc('timezone', timestamp with time zone 'infinity', 'GMT') AS notsupp_zone_trunc;
+SELECT date_trunc( 'week', timestamp with time zone 'infinity', 'GMT') AS inf_zone_trunc;
SELECT date_trunc('ago', timestamp with time zone 'infinity', 'GMT') AS invalid_zone_trunc;
-
-
-- verify date_bin behaves the same as date_trunc for relevant intervals
SELECT
str,