From 165932d9926ca1b6510e10a728d35d40a2ff7c2d Mon Sep 17 00:00:00 2001 From: Sebastian Harl Date: Wed, 7 Nov 2012 21:25:58 +0100 Subject: [PATCH] RRTimeslice: Added rrtimeslice_cmp(). This function compares two timeslices by timestamp. It returns values less than zero, zero or greater than zero if the first timestamp is smaller than, equal to or greater than the second. Values -2 / 2 indicate that the sequence numbers don't match while values -1 / 1 indicate that they do match. --- src/postrr.h.in | 25 ++++++++++++++ src/postrr.sql.in | 5 +++ src/rrtimeslice.c | 86 ++++++++++++++++++++++++++++++++++++++--------- 3 files changed, 101 insertions(+), 15 deletions(-) diff --git a/src/postrr.h.in b/src/postrr.h.in index 206c682..d9df4af 100644 --- a/src/postrr.h.in +++ b/src/postrr.h.in @@ -83,6 +83,10 @@ rrtimeslice_to_timestamptz(PG_FUNCTION_ARGS); /* comparison operators */ Datum +rrtimeslice_cmp(PG_FUNCTION_ARGS); + +/* sequence comparison operators */ +Datum rrtimeslice_seq_eq(PG_FUNCTION_ARGS); Datum rrtimeslice_seq_ne(PG_FUNCTION_ARGS); @@ -103,6 +107,27 @@ rrtimeslice_seq_hash(PG_FUNCTION_ARGS); * internal (not fmgr-callable) functions */ +/* + * compare two RRTimeslices + * + * returns: + * - -2 if ts1 < ts2 (sequence numbers don't match) + * - -1 if ts1 < ts2 (sequence numbers match) + * - 0 if ts1 = ts2 + * - 1 if ts1 > ts2 (sequence numbers match) + * - 2 if ts1 > ts2 (sequence numbers don't match) + */ +int +rrtimeslice_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2); + +/* + * compare sequence numbers of two RRTimeslices + * + * returns: + * - -1 if ts1 < ts2 + * - 0 if ts1 = ts2 + * - 1 if ts1 > ts2 + */ int rrtimeslice_seq_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2); diff --git a/src/postrr.sql.in b/src/postrr.sql.in index fc32f43..87ef9d3 100644 --- a/src/postrr.sql.in +++ b/src/postrr.sql.in @@ -117,6 +117,11 @@ CREATE CAST (rrtimeslice AS timestamptz) WITH FUNCTION Tstamptz(rrtimeslice); -- EXPLICIT +CREATE OR REPLACE FUNCTION rrtimeslice_cmp(rrtimeslice, rrtimeslice) + RETURNS integer + AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_cmp' + LANGUAGE 'C' IMMUTABLE STRICT; + CREATE OR REPLACE FUNCTION rrtimeslice_seq_eq(rrtimeslice, rrtimeslice) RETURNS boolean AS 'postrr-@POSTRR_MAJOR_VERSION@.@POSTRR_MINOR_VERSION@', 'rrtimeslice_seq_eq' diff --git a/src/rrtimeslice.c b/src/rrtimeslice.c index 25e9cb3..7de9ed7 100644 --- a/src/rrtimeslice.c +++ b/src/rrtimeslice.c @@ -195,6 +195,43 @@ rrtimeslice_apply_typmod(rrtimeslice_t *tslice, int32 typmod) return 0; } /* rrtimeslice_apply_typmod */ +/* + * rrtimeslice_cmp_unify: + * Unify two RRTimeslices in order to prepare them for comparison. That is, if + * either one of the arguments does not have any typmod applied, then apply + * the typmod of the other argument. Throws an error if the typmods don't + * match. + * + * Returns: + * - 0 if the arguments could be unified + * - 1 if only the first argument is NULL + * - 2 if both arguments are NULL + * - 3 if only the second argument is NULL + */ +static int +rrtimeslice_cmp_unify(rrtimeslice_t *ts1, rrtimeslice_t *ts2) +{ + if ((! ts1) && (! ts2)) + return 0; + else if (! ts1) + return -1; + else if (! ts2) + return 1; + + if (ts1->tsid && (! ts2->tsid)) + rrtimeslice_apply_typmod(ts2, ts1->tsid); + else if ((! ts1->tsid) && ts2->tsid) + rrtimeslice_apply_typmod(ts1, ts2->tsid); + + if (ts1->tsid != ts2->tsid) /* XXX: compare len/num */ + ereport(ERROR, ( + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid comparison: cannot compare " + "rrtimeslices with different typmods (yet)") + )); + return 0; +} /* rrtimeslice_cmp_unify */ + /* * prototypes for PostgreSQL functions */ @@ -209,6 +246,8 @@ PG_FUNCTION_INFO_V1(rrtimeslice_typmodout); PG_FUNCTION_INFO_V1(rrtimeslice_to_rrtimeslice); PG_FUNCTION_INFO_V1(rrtimeslice_to_timestamptz); +PG_FUNCTION_INFO_V1(rrtimeslice_cmp); + PG_FUNCTION_INFO_V1(rrtimeslice_seq_eq); PG_FUNCTION_INFO_V1(rrtimeslice_seq_ne); PG_FUNCTION_INFO_V1(rrtimeslice_seq_lt); @@ -490,26 +529,43 @@ rrtimeslice_to_timestamptz(PG_FUNCTION_ARGS) } /* rrtimeslice_to_timestamptz */ int -rrtimeslice_seq_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2) +rrtimeslice_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2) { - if ((! ts1) && (! ts2)) + int status; + + status = rrtimeslice_cmp_unify(ts1, ts2); + if (status) /* [1, 3] -> [-1, 1] */ + return status - 2; + + if (ts1->tstamp == ts2->tstamp) return 0; - else if (! ts1) + else if ((ts1->seq == ts2->seq) && (ts1->tstamp < ts2->tstamp)) return -1; - else if (! ts2) + else if (ts1->tstamp < ts2->tstamp) + return -2; + else if ((ts1->seq == ts2->seq) && (ts1->tstamp > ts2->tstamp)) return 1; + else + return 2; +} /* rrtimeslice_cmp_internal */ - if (ts1->tsid && (! ts2->tsid)) - rrtimeslice_apply_typmod(ts2, ts1->tsid); - else if ((! ts1->tsid) && ts2->tsid) - rrtimeslice_apply_typmod(ts1, ts2->tsid); +Datum +rrtimeslice_cmp(PG_FUNCTION_ARGS) +{ + rrtimeslice_t *ts1 = PG_GETARG_RRTIMESLICE_P(0); + rrtimeslice_t *ts2 = PG_GETARG_RRTIMESLICE_P(1); - if (ts1->tsid != ts2->tsid) /* XXX: compare len/num */ - ereport(ERROR, ( - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("invalid comparison: cannot compare " - "rrtimeslices with different typmods (yet)") - )); + PG_RETURN_INT32(rrtimeslice_cmp_internal(ts1, ts2)); +} /* rrtimeslice_cmp */ + +int +rrtimeslice_seq_cmp_internal(rrtimeslice_t *ts1, rrtimeslice_t *ts2) +{ + int status; + + status = rrtimeslice_cmp_unify(ts1, ts2); + if (status) /* [1, 3] -> [-1, 1] */ + return status - 2; if (ts1->seq < ts2->seq) return -1; @@ -580,7 +636,7 @@ rrtimeslice_seq_cmp(PG_FUNCTION_ARGS) rrtimeslice_t *ts2 = PG_GETARG_RRTIMESLICE_P(1); PG_RETURN_INT32(rrtimeslice_seq_cmp_internal(ts1, ts2)); -} /* rrtimeslice_seq_ge */ +} /* rrtimeslice_seq_cmp */ Datum rrtimeslice_seq_hash(PG_FUNCTION_ARGS) -- 2.30.2