LCOV - code coverage report
Current view: top level - src/backend/utils/adt - xid.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 66.7 % 147 98
Test Date: 2026-02-17 17:20:33 Functions: 65.7 % 35 23
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*-------------------------------------------------------------------------
       2              :  *
       3              :  * xid.c
       4              :  *    POSTGRES transaction identifier and command identifier datatypes.
       5              :  *
       6              :  * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
       7              :  * Portions Copyright (c) 1994, Regents of the University of California
       8              :  *
       9              :  *
      10              :  * IDENTIFICATION
      11              :  *    src/backend/utils/adt/xid.c
      12              :  *
      13              :  *-------------------------------------------------------------------------
      14              :  */
      15              : #include "postgres.h"
      16              : 
      17              : #include <limits.h>
      18              : 
      19              : #include "access/multixact.h"
      20              : #include "access/transam.h"
      21              : #include "access/xact.h"
      22              : #include "common/hashfn.h"
      23              : #include "common/int.h"
      24              : #include "libpq/pqformat.h"
      25              : #include "utils/builtins.h"
      26              : #include "utils/xid8.h"
      27              : 
      28              : #define PG_GETARG_COMMANDID(n)      DatumGetCommandId(PG_GETARG_DATUM(n))
      29              : #define PG_RETURN_COMMANDID(x)      return CommandIdGetDatum(x)
      30              : 
      31              : 
      32              : Datum
      33       201120 : xidin(PG_FUNCTION_ARGS)
      34              : {
      35       201120 :     char       *str = PG_GETARG_CSTRING(0);
      36              :     TransactionId result;
      37              : 
      38       201120 :     result = uint32in_subr(str, NULL, "xid", fcinfo->context);
      39       201114 :     PG_RETURN_TRANSACTIONID(result);
      40              : }
      41              : 
      42              : Datum
      43       137357 : xidout(PG_FUNCTION_ARGS)
      44              : {
      45       137357 :     TransactionId transactionId = PG_GETARG_TRANSACTIONID(0);
      46       137357 :     char       *result = (char *) palloc(16);
      47              : 
      48       137357 :     snprintf(result, 16, "%u", transactionId);
      49       137357 :     PG_RETURN_CSTRING(result);
      50              : }
      51              : 
      52              : /*
      53              :  *      xidrecv         - converts external binary format to xid
      54              :  */
      55              : Datum
      56            0 : xidrecv(PG_FUNCTION_ARGS)
      57              : {
      58            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
      59              : 
      60            0 :     PG_RETURN_TRANSACTIONID((TransactionId) pq_getmsgint(buf, sizeof(TransactionId)));
      61              : }
      62              : 
      63              : /*
      64              :  *      xidsend         - converts xid to binary format
      65              :  */
      66              : Datum
      67            0 : xidsend(PG_FUNCTION_ARGS)
      68              : {
      69            0 :     TransactionId arg1 = PG_GETARG_TRANSACTIONID(0);
      70              :     StringInfoData buf;
      71              : 
      72            0 :     pq_begintypsend(&buf);
      73            0 :     pq_sendint32(&buf, arg1);
      74            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
      75              : }
      76              : 
      77              : /*
      78              :  *      xideq           - are two xids equal?
      79              :  */
      80              : Datum
      81       277053 : xideq(PG_FUNCTION_ARGS)
      82              : {
      83       277053 :     TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
      84       277053 :     TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
      85              : 
      86       277053 :     PG_RETURN_BOOL(TransactionIdEquals(xid1, xid2));
      87              : }
      88              : 
      89              : /*
      90              :  *      xidneq          - are two xids different?
      91              :  */
      92              : Datum
      93          443 : xidneq(PG_FUNCTION_ARGS)
      94              : {
      95          443 :     TransactionId xid1 = PG_GETARG_TRANSACTIONID(0);
      96          443 :     TransactionId xid2 = PG_GETARG_TRANSACTIONID(1);
      97              : 
      98          443 :     PG_RETURN_BOOL(!TransactionIdEquals(xid1, xid2));
      99              : }
     100              : 
     101              : Datum
     102           96 : hashxid(PG_FUNCTION_ARGS)
     103              : {
     104           96 :     return hash_uint32(PG_GETARG_TRANSACTIONID(0));
     105              : }
     106              : 
     107              : Datum
     108            0 : hashxidextended(PG_FUNCTION_ARGS)
     109              : {
     110            0 :     return hash_uint32_extended(PG_GETARG_TRANSACTIONID(0), PG_GETARG_INT64(1));
     111              : }
     112              : 
     113              : /*
     114              :  *      xid_age         - compute age of an XID (relative to latest stable xid)
     115              :  */
     116              : Datum
     117          151 : xid_age(PG_FUNCTION_ARGS)
     118              : {
     119          151 :     TransactionId xid = PG_GETARG_TRANSACTIONID(0);
     120          151 :     TransactionId now = GetStableLatestTransactionId();
     121              : 
     122              :     /* Permanent XIDs are always infinitely old */
     123          151 :     if (!TransactionIdIsNormal(xid))
     124            0 :         PG_RETURN_INT32(INT_MAX);
     125              : 
     126          151 :     PG_RETURN_INT32((int32) (now - xid));
     127              : }
     128              : 
     129              : /*
     130              :  *      mxid_age            - compute age of a multi XID (relative to latest stable mxid)
     131              :  */
     132              : Datum
     133            1 : mxid_age(PG_FUNCTION_ARGS)
     134              : {
     135            1 :     TransactionId xid = PG_GETARG_TRANSACTIONID(0);
     136            1 :     MultiXactId now = ReadNextMultiXactId();
     137              : 
     138            1 :     if (!MultiXactIdIsValid(xid))
     139            0 :         PG_RETURN_INT32(INT_MAX);
     140              : 
     141            1 :     PG_RETURN_INT32((int32) (now - xid));
     142              : }
     143              : 
     144              : /*
     145              :  * xidComparator
     146              :  *      qsort comparison function for XIDs
     147              :  *
     148              :  * We can't use wraparound comparison for XIDs because that does not respect
     149              :  * the triangle inequality!  Any old sort order will do.
     150              :  */
     151              : int
     152        33099 : xidComparator(const void *arg1, const void *arg2)
     153              : {
     154        33099 :     TransactionId xid1 = *(const TransactionId *) arg1;
     155        33099 :     TransactionId xid2 = *(const TransactionId *) arg2;
     156              : 
     157        33099 :     return pg_cmp_u32(xid1, xid2);
     158              : }
     159              : 
     160              : /*
     161              :  * xidLogicalComparator
     162              :  *      qsort comparison function for XIDs
     163              :  *
     164              :  * This is used to compare only XIDs from the same epoch (e.g. for backends
     165              :  * running at the same time). So there must be only normal XIDs, so there's
     166              :  * no issue with triangle inequality.
     167              :  */
     168              : int
     169            0 : xidLogicalComparator(const void *arg1, const void *arg2)
     170              : {
     171            0 :     TransactionId xid1 = *(const TransactionId *) arg1;
     172            0 :     TransactionId xid2 = *(const TransactionId *) arg2;
     173              : 
     174              :     Assert(TransactionIdIsNormal(xid1));
     175              :     Assert(TransactionIdIsNormal(xid2));
     176              : 
     177            0 :     if (TransactionIdPrecedes(xid1, xid2))
     178            0 :         return -1;
     179              : 
     180            0 :     if (TransactionIdPrecedes(xid2, xid1))
     181            0 :         return 1;
     182              : 
     183            0 :     return 0;
     184              : }
     185              : 
     186              : Datum
     187          844 : xid8toxid(PG_FUNCTION_ARGS)
     188              : {
     189          844 :     FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
     190              : 
     191          844 :     PG_RETURN_TRANSACTIONID(XidFromFullTransactionId(fxid));
     192              : }
     193              : 
     194              : Datum
     195          434 : xid8in(PG_FUNCTION_ARGS)
     196              : {
     197          434 :     char       *str = PG_GETARG_CSTRING(0);
     198              :     uint64      result;
     199              : 
     200          434 :     result = uint64in_subr(str, NULL, "xid8", fcinfo->context);
     201          428 :     PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(result));
     202              : }
     203              : 
     204              : Datum
     205          493 : xid8out(PG_FUNCTION_ARGS)
     206              : {
     207          493 :     FullTransactionId fxid = PG_GETARG_FULLTRANSACTIONID(0);
     208          493 :     char       *result = (char *) palloc(21);
     209              : 
     210          493 :     snprintf(result, 21, UINT64_FORMAT, U64FromFullTransactionId(fxid));
     211          493 :     PG_RETURN_CSTRING(result);
     212              : }
     213              : 
     214              : Datum
     215            0 : xid8recv(PG_FUNCTION_ARGS)
     216              : {
     217            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     218              :     uint64      value;
     219              : 
     220            0 :     value = (uint64) pq_getmsgint64(buf);
     221            0 :     PG_RETURN_FULLTRANSACTIONID(FullTransactionIdFromU64(value));
     222              : }
     223              : 
     224              : Datum
     225            0 : xid8send(PG_FUNCTION_ARGS)
     226              : {
     227            0 :     FullTransactionId arg1 = PG_GETARG_FULLTRANSACTIONID(0);
     228              :     StringInfoData buf;
     229              : 
     230            0 :     pq_begintypsend(&buf);
     231            0 :     pq_sendint64(&buf, (uint64) U64FromFullTransactionId(arg1));
     232            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     233              : }
     234              : 
     235              : Datum
     236            9 : xid8eq(PG_FUNCTION_ARGS)
     237              : {
     238            9 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     239            9 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     240              : 
     241            9 :     PG_RETURN_BOOL(FullTransactionIdEquals(fxid1, fxid2));
     242              : }
     243              : 
     244              : Datum
     245            4 : xid8ne(PG_FUNCTION_ARGS)
     246              : {
     247            4 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     248            4 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     249              : 
     250            4 :     PG_RETURN_BOOL(!FullTransactionIdEquals(fxid1, fxid2));
     251              : }
     252              : 
     253              : Datum
     254            9 : xid8lt(PG_FUNCTION_ARGS)
     255              : {
     256            9 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     257            9 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     258              : 
     259            9 :     PG_RETURN_BOOL(FullTransactionIdPrecedes(fxid1, fxid2));
     260              : }
     261              : 
     262              : Datum
     263            9 : xid8gt(PG_FUNCTION_ARGS)
     264              : {
     265            9 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     266            9 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     267              : 
     268            9 :     PG_RETURN_BOOL(FullTransactionIdFollows(fxid1, fxid2));
     269              : }
     270              : 
     271              : Datum
     272            9 : xid8le(PG_FUNCTION_ARGS)
     273              : {
     274            9 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     275            9 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     276              : 
     277            9 :     PG_RETURN_BOOL(FullTransactionIdPrecedesOrEquals(fxid1, fxid2));
     278              : }
     279              : 
     280              : Datum
     281           21 : xid8ge(PG_FUNCTION_ARGS)
     282              : {
     283           21 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     284           21 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     285              : 
     286           21 :     PG_RETURN_BOOL(FullTransactionIdFollowsOrEquals(fxid1, fxid2));
     287              : }
     288              : 
     289              : Datum
     290           21 : xid8cmp(PG_FUNCTION_ARGS)
     291              : {
     292           21 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     293           21 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     294              : 
     295           21 :     if (FullTransactionIdFollows(fxid1, fxid2))
     296            3 :         PG_RETURN_INT32(1);
     297           18 :     else if (FullTransactionIdEquals(fxid1, fxid2))
     298            6 :         PG_RETURN_INT32(0);
     299              :     else
     300           12 :         PG_RETURN_INT32(-1);
     301              : }
     302              : 
     303              : Datum
     304           15 : hashxid8(PG_FUNCTION_ARGS)
     305              : {
     306           15 :     return hashint8(fcinfo);
     307              : }
     308              : 
     309              : Datum
     310            0 : hashxid8extended(PG_FUNCTION_ARGS)
     311              : {
     312            0 :     return hashint8extended(fcinfo);
     313              : }
     314              : 
     315              : Datum
     316           12 : xid8_larger(PG_FUNCTION_ARGS)
     317              : {
     318           12 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     319           12 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     320              : 
     321           12 :     if (FullTransactionIdFollows(fxid1, fxid2))
     322            0 :         PG_RETURN_FULLTRANSACTIONID(fxid1);
     323              :     else
     324           12 :         PG_RETURN_FULLTRANSACTIONID(fxid2);
     325              : }
     326              : 
     327              : Datum
     328           12 : xid8_smaller(PG_FUNCTION_ARGS)
     329              : {
     330           12 :     FullTransactionId fxid1 = PG_GETARG_FULLTRANSACTIONID(0);
     331           12 :     FullTransactionId fxid2 = PG_GETARG_FULLTRANSACTIONID(1);
     332              : 
     333           12 :     if (FullTransactionIdPrecedes(fxid1, fxid2))
     334           12 :         PG_RETURN_FULLTRANSACTIONID(fxid1);
     335              :     else
     336            0 :         PG_RETURN_FULLTRANSACTIONID(fxid2);
     337              : }
     338              : 
     339              : /*****************************************************************************
     340              :  *   COMMAND IDENTIFIER ROUTINES                                             *
     341              :  *****************************************************************************/
     342              : 
     343              : /*
     344              :  *      cidin   - converts CommandId to internal representation.
     345              :  */
     346              : Datum
     347            3 : cidin(PG_FUNCTION_ARGS)
     348              : {
     349            3 :     char       *str = PG_GETARG_CSTRING(0);
     350              :     CommandId   result;
     351              : 
     352            3 :     result = uint32in_subr(str, NULL, "cid", fcinfo->context);
     353            3 :     PG_RETURN_COMMANDID(result);
     354              : }
     355              : 
     356              : /*
     357              :  *      cidout  - converts a cid to external representation.
     358              :  */
     359              : Datum
     360           97 : cidout(PG_FUNCTION_ARGS)
     361              : {
     362           97 :     CommandId   c = PG_GETARG_COMMANDID(0);
     363           97 :     char       *result = (char *) palloc(16);
     364              : 
     365           97 :     snprintf(result, 16, "%u", c);
     366           97 :     PG_RETURN_CSTRING(result);
     367              : }
     368              : 
     369              : /*
     370              :  *      cidrecv         - converts external binary format to cid
     371              :  */
     372              : Datum
     373            0 : cidrecv(PG_FUNCTION_ARGS)
     374              : {
     375            0 :     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
     376              : 
     377            0 :     PG_RETURN_COMMANDID((CommandId) pq_getmsgint(buf, sizeof(CommandId)));
     378              : }
     379              : 
     380              : /*
     381              :  *      cidsend         - converts cid to binary format
     382              :  */
     383              : Datum
     384            0 : cidsend(PG_FUNCTION_ARGS)
     385              : {
     386            0 :     CommandId   arg1 = PG_GETARG_COMMANDID(0);
     387              :     StringInfoData buf;
     388              : 
     389            0 :     pq_begintypsend(&buf);
     390            0 :     pq_sendint32(&buf, arg1);
     391            0 :     PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
     392              : }
     393              : 
     394              : Datum
     395            0 : cideq(PG_FUNCTION_ARGS)
     396              : {
     397            0 :     CommandId   arg1 = PG_GETARG_COMMANDID(0);
     398            0 :     CommandId   arg2 = PG_GETARG_COMMANDID(1);
     399              : 
     400            0 :     PG_RETURN_BOOL(arg1 == arg2);
     401              : }
     402              : 
     403              : Datum
     404            0 : hashcid(PG_FUNCTION_ARGS)
     405              : {
     406            0 :     return hash_uint32(PG_GETARG_COMMANDID(0));
     407              : }
     408              : 
     409              : Datum
     410            0 : hashcidextended(PG_FUNCTION_ARGS)
     411              : {
     412            0 :     return hash_uint32_extended(PG_GETARG_COMMANDID(0), PG_GETARG_INT64(1));
     413              : }
        

Generated by: LCOV version 2.0-1