/*------------------------------------------------------------------------- * * xid.c * POSTGRES transaction identifier and command identifier datatypes. * * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * src/backend/utils/adt/xid.c * *------------------------------------------------------------------------- */ #include "postgres.h" #include #include "access/multixact.h" #include "access/transam.h" #include "access/xact.h" #include "libpq/pqformat.h" #include "utils/builtins.h" #define PG_GETARG_TRANSACTIONID(n) DatumGetTransactionId(PG_GETARG_DATUM(n)) #define PG_RETURN_TRANSACTIONID(x) return TransactionIdGetDatum(x) #define PG_GETARG_COMMANDID(n) DatumGetCommandId(PG_GETARG_DATUM(n)) #define PG_RETURN_COMMANDID(x) return CommandIdGetDatum(x) Datum xidin(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); PG_RETURN_TRANSACTIONID((TransactionId) strtoul(str, NULL, 0)); } Datum xidout(PG_FUNCTION_ARGS) { TransactionId transactionId = PG_GETARG_TRANSACTIONID(0); /* maximum 32 bit unsigned integer representation takes 10 chars */ char *str = palloc(11); snprintf(str, 11, "%lu", (unsigned long) transactionId); PG_RETURN_CSTRING(str); } /* * xidrecv - converts external binary format to xid */ Datum xidrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_TRANSACTIONID((TransactionId) pq_getmsgint(buf, sizeof(TransactionId))); } /* * xidsend - converts xid to binary format */ Datum xidsend(PG_FUNCTION_ARGS) { TransactionId arg1 = PG_GETARG_TRANSACTIONID(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendint(&buf, arg1, sizeof(arg1)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } /* * xideq - are two xids equal? */ Datum xideq(PG_FUNCTION_ARGS) { TransactionId xid1 = PG_GETARG_TRANSACTIONID(0); TransactionId xid2 = PG_GETARG_TRANSACTIONID(1); PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2)); } /* * xidneq - are two xids different? */ Datum xidneq(PG_FUNCTION_ARGS) { TransactionId xid1 = PG_GETARG_TRANSACTIONID(0); TransactionId xid2 = PG_GETARG_TRANSACTIONID(1); PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2)); } /* * xid_age - compute age of an XID (relative to latest stable xid) */ Datum xid_age(PG_FUNCTION_ARGS) { TransactionId xid = PG_GETARG_TRANSACTIONID(0); TransactionId now = GetStableLatestTransactionId(); /* Permanent XIDs are always infinitely old */ if (!TransactionIdIsNormal(xid)) PG_RETURN_INT32(INT_MAX); PG_RETURN_INT32((int32) (now - xid)); } /* * mxid_age - compute age of a multi XID (relative to latest stable mxid) */ Datum mxid_age(PG_FUNCTION_ARGS) { TransactionId xid = PG_GETARG_TRANSACTIONID(0); MultiXactId now = ReadNextMultiXactId(); if (!MultiXactIdIsValid(xid)) PG_RETURN_INT32(INT_MAX); PG_RETURN_INT32((int32) (now - xid)); } /* * xidComparator * qsort comparison function for XIDs * * We can't use wraparound comparison for XIDs because that does not respect * the triangle inequality! Any old sort order will do. */ int xidComparator(const void *arg1, const void *arg2) { TransactionId xid1 = *(const TransactionId *) arg1; TransactionId xid2 = *(const TransactionId *) arg2; if (xid1 > xid2) return 1; if (xid1 < xid2) return -1; return 0; } /***************************************************************************** * COMMAND IDENTIFIER ROUTINES * *****************************************************************************/ /* * cidin - converts CommandId to internal representation. */ Datum cidin(PG_FUNCTION_ARGS) { char *s = PG_GETARG_CSTRING(0); CommandId c; c = atoi(s); PG_RETURN_COMMANDID(c); } /* * cidout - converts a cid to external representation. */ Datum cidout(PG_FUNCTION_ARGS) { CommandId c = PG_GETARG_COMMANDID(0); char *result = (char *) palloc(16); snprintf(result, 16, "%u", (unsigned int) c); PG_RETURN_CSTRING(result); } /* * cidrecv - converts external binary format to cid */ Datum cidrecv(PG_FUNCTION_ARGS) { StringInfo buf = (StringInfo) PG_GETARG_POINTER(0); PG_RETURN_COMMANDID((CommandId) pq_getmsgint(buf, sizeof(CommandId))); } /* * cidsend - converts cid to binary format */ Datum cidsend(PG_FUNCTION_ARGS) { CommandId arg1 = PG_GETARG_COMMANDID(0); StringInfoData buf; pq_begintypsend(&buf); pq_sendint(&buf, arg1, sizeof(arg1)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } Datum cideq(PG_FUNCTION_ARGS) { CommandId arg1 = PG_GETARG_COMMANDID(0); CommandId arg2 = PG_GETARG_COMMANDID(1); PG_RETURN_BOOL(arg1 == arg2); }