diff --git a/src/backend/utils/adt/Makefile b/src/backend/utils/adt/Makefile index 5f968b0..e79aeef 100644 --- a/src/backend/utils/adt/Makefile +++ b/src/backend/utils/adt/Makefile @@ -18,7 +18,7 @@ endif OBJS = acl.o arrayfuncs.o array_userfuncs.o arrayutils.o bool.o \ cash.o char.o date.o datetime.o datum.o domains.o \ enum.o float.o format_type.o \ - geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o \ + geo_ops.o geo_selfuncs.o int.o int8.o like.o lockfuncs.o lsn.o \ misc.o nabstime.o name.o numeric.o numutils.o \ oid.o oracle_compat.o pseudotypes.o rangetypes.o rangetypes_gist.o \ rowtypes.o regexp.o regproc.o ruleutils.o selfuncs.o \ diff --git a/src/backend/utils/adt/lsn.c b/src/backend/utils/adt/lsn.c new file mode 100644 index 0000000..839ff37 --- /dev/null +++ b/src/backend/utils/adt/lsn.c @@ -0,0 +1,189 @@ +/*------------------------------------------------------------------------- + * + * lsn.c + * Internal LSN operations + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/utils/adt/lsn.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include "funcapi.h" +#include "libpq/pqformat.h" +#include "utils/builtins.h" +#include "utils/lsn.h" + +#define MAXINT4LEN 12 +#define MAXINT8LEN 25 +#define MAXLSNLEN 17 +#define MAXLSNCOMPONENT 8 + +/*---------------------------------------------------------- + * Formatting and conversion routines. + *---------------------------------------------------------*/ + +Datum +lsn_in(PG_FUNCTION_ARGS) +{ + char *str = PG_GETARG_CSTRING(0); + int len1, + len2; + XLogRecPtr *result; + + /* Sanity check input format. */ + len1 = strspn(str, "0123456789abcdefABCDEF"); + if (len1 < 1 || len1 > MAXLSNCOMPONENT || str[len1] != '/') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for lsn: \"%s\"", str))); + len2 = strspn(str + len1 + 1, "0123456789abcdefABCDEF"); + if (len2 < 1 || len2 > MAXLSNCOMPONENT || str[len1 + 1 + len2] != '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("invalid input syntax for lsn: \"%s\"", str))); + + /* Decode result. */ + result = palloc(sizeof(XLogRecPtr)); + result->xlogid = (uint32) strtoul(str, NULL, 16); + result->xrecoff = (uint32) strtoul(str + len1 + 1, NULL, 16); + + PG_RETURN_POINTER(result); +} + +Datum +lsn_out(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn = (XLogRecPtr *) PG_GETARG_POINTER(0); + char buf[MAXLSNLEN + 1]; + char *result; + + sprintf(buf, "%X/%X", lsn->xlogid, lsn->xrecoff); + result = pstrdup(buf); + PG_RETURN_CSTRING(result); +} + +Datum +lsn_recv(PG_FUNCTION_ARGS) +{ + StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); + XLogRecPtr *result; + + result = palloc(sizeof(XLogRecPtr)); + result->xlogid = pq_getmsgint(buf, 4); + result->xrecoff = pq_getmsgint(buf, 4); + + PG_RETURN_POINTER(result); +} + +Datum +lsn_send(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn = (XLogRecPtr *) PG_GETARG_POINTER(0); + StringInfoData buf; + + pq_begintypsend(&buf); + pq_sendint(&buf, lsn->xlogid, 4); + pq_sendint(&buf, lsn->xrecoff, 4); + PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); +} + + +/*---------------------------------------------------------- + * Relational operators for LSNs + *---------------------------------------------------------*/ + +Datum +lsn_eq(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(XLByteEQ(*lsn1, *lsn2)); +} + +Datum +lsn_ne(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(!XLByteEQ(*lsn1, *lsn2)); +} + +Datum +lsn_lt(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(XLByteLT(*lsn1, *lsn2)); +} + +Datum +lsn_gt(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + /* note order of arguments */ + PG_RETURN_BOOL(XLByteLT(*lsn2, *lsn1)); +} + +Datum +lsn_le(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + PG_RETURN_BOOL(XLByteLE(*lsn1, *lsn2)); +} + +Datum +lsn_ge(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + + /* note order of arguments */ + PG_RETURN_BOOL(XLByteLE(*lsn2, *lsn1)); +} + + +/*---------------------------------------------------------- + * Arithmetic operators on LSNs. + *---------------------------------------------------------*/ + +Datum +lsn_mi(PG_FUNCTION_ARGS) +{ + XLogRecPtr *lsn1 = (XLogRecPtr *) PG_GETARG_POINTER(0); + XLogRecPtr *lsn2 = (XLogRecPtr *) PG_GETARG_POINTER(1); + uint64 v1; + uint64 v2; + char buf[256]; + Datum result; + + /* Flatten values to 64-bit unsigned integers. */ + v1 = (((uint64) lsn1->xlogid) << 32) | ((uint64) lsn1->xrecoff); + v2 = (((uint64) lsn2->xlogid) << 32) | ((uint64) lsn2->xrecoff); + + /* Negative results are not allowed. */ + if (v1 < v2) + ereport(ERROR, + (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), + errmsg("LSN out of range"))); + + /* Convert to numeric. */ + sprintf(buf, UINT64_FORMAT, v1 - v2); + result = DirectFunctionCall3(numeric_in, + CStringGetDatum(buf), + ObjectIdGetDatum(0), + Int32GetDatum(-1)); + + return result; +} diff --git a/src/include/catalog/pg_operator.h b/src/include/catalog/pg_operator.h index eac5cb9..07b8f63 100644 --- a/src/include/catalog/pg_operator.h +++ b/src/include/catalog/pg_operator.h @@ -1578,6 +1578,22 @@ DESCR("less than or equal"); DATA(insert OID = 2977 ( ">=" PGNSP PGUID b f f 2950 2950 16 2976 2974 uuid_ge scalargtsel scalargtjoinsel )); DESCR("greater than or equal"); +/* lsn operators */ +DATA(insert OID = 3788 ( "=" PGNSP PGUID b f f 3813 3813 16 3788 3789 lsn_eq eqsel eqjoinsel )); +DESCR("equal"); +DATA(insert OID = 3789 ( "<>" PGNSP PGUID b f f 3813 3813 16 3789 3788 lsn_ne neqsel neqjoinsel )); +DESCR("not equal"); +DATA(insert OID = 3790 ( "<" PGNSP PGUID b f f 3813 3813 16 3791 3793 lsn_lt scalarltsel scalarltjoinsel )); +DESCR("less than"); +DATA(insert OID = 3791 ( ">" PGNSP PGUID b f f 3813 3813 16 3790 3792 lsn_gt scalargtsel scalargtjoinsel )); +DESCR("greater than"); +DATA(insert OID = 3792 ( "<=" PGNSP PGUID b f f 3813 3813 16 3793 3791 lsn_le scalarltsel scalarltjoinsel )); +DESCR("less than or equal"); +DATA(insert OID = 3793 ( ">=" PGNSP PGUID b f f 3813 3813 16 3792 3790 lsn_ge scalargtsel scalargtjoinsel )); +DESCR("greater than or equal"); +DATA(insert OID = 3795 ( "-" PGNSP PGUID b f f 3813 3813 1700 0 0 lsn_mi - - )); +DESCR("minus"); + /* enum operators */ DATA(insert OID = 3516 ( "=" PGNSP PGUID b t t 3500 3500 16 3516 3517 enum_eq eqsel eqjoinsel )); DESCR("equal"); diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index 28e53b7..0ddc956 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -3983,6 +3983,23 @@ DESCR("I/O"); DATA(insert OID = 2963 ( uuid_hash PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 23 "2950" _null_ _null_ _null_ _null_ uuid_hash _null_ _null_ _null_ )); DESCR("hash"); +/* lsn */ +DATA(insert OID = 3778 ( lsn_in PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3813 "2275" _null_ _null_ _null_ _null_ lsn_in _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3779 ( lsn_out PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 2275 "3813" _null_ _null_ _null_ _null_ lsn_out _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3780 ( lsn_lt PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_lt _null_ _null_ _null_ )); +DATA(insert OID = 3781 ( lsn_le PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_le _null_ _null_ _null_ )); +DATA(insert OID = 3782 ( lsn_eq PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_eq _null_ _null_ _null_ )); +DATA(insert OID = 3783 ( lsn_ge PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_ge _null_ _null_ _null_ )); +DATA(insert OID = 3784 ( lsn_gt PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_gt _null_ _null_ _null_ )); +DATA(insert OID = 3785 ( lsn_ne PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 16 "3813 3813" _null_ _null_ _null_ _null_ lsn_ne _null_ _null_ _null_ )); +DATA(insert OID = 3794 ( lsn_mi PGNSP PGUID 12 1 0 0 0 f f f t f i 2 0 1700 "3813 3813" _null_ _null_ _null_ _null_ lsn_mi _null_ _null_ _null_ )); +DATA(insert OID = 3786 ( lsn_recv PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3813 "2281" _null_ _null_ _null_ _null_ lsn_recv _null_ _null_ _null_ )); +DESCR("I/O"); +DATA(insert OID = 3787 ( lsn_send PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 17 "3813" _null_ _null_ _null_ _null_ lsn_send _null_ _null_ _null_ )); +DESCR("I/O"); + /* enum related procs */ DATA(insert OID = 3504 ( anyenum_in PGNSP PGUID 12 1 0 0 0 f f f t f i 1 0 3500 "2275" _null_ _null_ _null_ _null_ anyenum_in _null_ _null_ _null_ )); DESCR("I/O"); diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 406241a..aec9a24 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -565,6 +565,11 @@ DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in u DESCR("UUID datatype"); DATA(insert OID = 2951 ( _uuid PGNSP PGUID -1 f b A f t \054 0 2950 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ )); +/* lsn */ +DATA(insert OID = 3813 ( lsn PGNSP PGUID 16 f b U f t \054 0 0 3814 lsn_in lsn_out lsn_recv lsn_send - - - i p f 0 -1 0 0 _null_ _null_ )); +DESCR("LSN datatype"); +DATA(insert OID = 3814 ( _lsn PGNSP PGUID -1 f b A f t \054 0 3813 0 array_in array_out array_recv array_send - - - i x f 0 -1 0 0 _null_ _null_ )); + /* text search */ DATA(insert OID = 3614 ( tsvector PGNSP PGUID -1 f b U f t \054 0 0 3643 tsvectorin tsvectorout tsvectorrecv tsvectorsend - - ts_typanalyze i x f 0 -1 0 0 _null_ _null_ )); DESCR("text representation for text search"); diff --git a/src/include/utils/lsn.h b/src/include/utils/lsn.h new file mode 100644 index 0000000..7e4be7b --- /dev/null +++ b/src/include/utils/lsn.h @@ -0,0 +1,33 @@ +/*------------------------------------------------------------------------- + * + * lsn.h + * Declarations for operations on log sequence numbers (LSNs). + * + * + * Portions Copyright (c) 1996-2011, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * src/include/utils/lsn.h + * + *------------------------------------------------------------------------- + */ +#ifndef LSN_H +#define LSN_H + +#include "fmgr.h" + +extern Datum lsn_in(PG_FUNCTION_ARGS); +extern Datum lsn_out(PG_FUNCTION_ARGS); +extern Datum lsn_recv(PG_FUNCTION_ARGS); +extern Datum lsn_send(PG_FUNCTION_ARGS); + +extern Datum lsn_eq(PG_FUNCTION_ARGS); +extern Datum lsn_ne(PG_FUNCTION_ARGS); +extern Datum lsn_lt(PG_FUNCTION_ARGS); +extern Datum lsn_gt(PG_FUNCTION_ARGS); +extern Datum lsn_le(PG_FUNCTION_ARGS); +extern Datum lsn_ge(PG_FUNCTION_ARGS); + +extern Datum lsn_mi(PG_FUNCTION_ARGS); + +#endif /* LSN_H */