LCOV - code coverage report
Current view: top level - src/backend/access/transam - xlogfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 0 182 0.0 %
Date: 2017-09-29 13:40:31 Functions: 0 21 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * xlogfuncs.c
       4             :  *
       5             :  * PostgreSQL write-ahead log manager user interface functions
       6             :  *
       7             :  * This file contains WAL control and information functions.
       8             :  *
       9             :  *
      10             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
      11             :  * Portions Copyright (c) 1994, Regents of the University of California
      12             :  *
      13             :  * src/backend/access/transam/xlogfuncs.c
      14             :  *
      15             :  *-------------------------------------------------------------------------
      16             :  */
      17             : #include "postgres.h"
      18             : 
      19             : #include "access/htup_details.h"
      20             : #include "access/xlog.h"
      21             : #include "access/xlog_internal.h"
      22             : #include "access/xlogutils.h"
      23             : #include "catalog/catalog.h"
      24             : #include "catalog/pg_type.h"
      25             : #include "funcapi.h"
      26             : #include "miscadmin.h"
      27             : #include "replication/walreceiver.h"
      28             : #include "storage/smgr.h"
      29             : #include "utils/builtins.h"
      30             : #include "utils/memutils.h"
      31             : #include "utils/numeric.h"
      32             : #include "utils/guc.h"
      33             : #include "utils/pg_lsn.h"
      34             : #include "utils/timestamp.h"
      35             : #include "utils/tuplestore.h"
      36             : #include "storage/fd.h"
      37             : #include "storage/ipc.h"
      38             : 
      39             : 
      40             : /*
      41             :  * Store label file and tablespace map during non-exclusive backups.
      42             :  */
      43             : static StringInfo label_file;
      44             : static StringInfo tblspc_map_file;
      45             : 
      46             : /*
      47             :  * Called when the backend exits with a running non-exclusive base backup,
      48             :  * to clean up state.
      49             :  */
      50             : static void
      51           0 : nonexclusive_base_backup_cleanup(int code, Datum arg)
      52             : {
      53           0 :     do_pg_abort_backup();
      54           0 :     ereport(WARNING,
      55             :             (errmsg("aborting backup due to backend exiting before pg_stop_backup was called")));
      56           0 : }
      57             : 
      58             : /*
      59             :  * pg_start_backup: set up for taking an on-line backup dump
      60             :  *
      61             :  * Essentially what this does is to create a backup label file in $PGDATA,
      62             :  * where it will be archived as part of the backup dump.  The label file
      63             :  * contains the user-supplied label string (typically this would be used
      64             :  * to tell where the backup dump will be stored) and the starting time and
      65             :  * starting WAL location for the dump.
      66             :  *
      67             :  * Permission checking for this function is managed through the normal
      68             :  * GRANT system.
      69             :  */
      70             : Datum
      71           0 : pg_start_backup(PG_FUNCTION_ARGS)
      72             : {
      73           0 :     text       *backupid = PG_GETARG_TEXT_PP(0);
      74           0 :     bool        fast = PG_GETARG_BOOL(1);
      75           0 :     bool        exclusive = PG_GETARG_BOOL(2);
      76             :     char       *backupidstr;
      77             :     XLogRecPtr  startpoint;
      78             :     DIR        *dir;
      79           0 :     SessionBackupState status = get_backup_status();
      80             : 
      81           0 :     backupidstr = text_to_cstring(backupid);
      82             : 
      83           0 :     if (status == SESSION_BACKUP_NON_EXCLUSIVE)
      84           0 :         ereport(ERROR,
      85             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
      86             :                  errmsg("a backup is already in progress in this session")));
      87             : 
      88             :     /* Make sure we can open the directory with tablespaces in it */
      89           0 :     dir = AllocateDir("pg_tblspc");
      90           0 :     if (!dir)
      91           0 :         ereport(ERROR,
      92             :                 (errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
      93             : 
      94           0 :     if (exclusive)
      95             :     {
      96           0 :         startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
      97             :                                         dir, NULL, NULL, false, true);
      98             :     }
      99             :     else
     100             :     {
     101             :         MemoryContext oldcontext;
     102             : 
     103             :         /*
     104             :          * Label file and tablespace map file need to be long-lived, since
     105             :          * they are read in pg_stop_backup.
     106             :          */
     107           0 :         oldcontext = MemoryContextSwitchTo(TopMemoryContext);
     108           0 :         label_file = makeStringInfo();
     109           0 :         tblspc_map_file = makeStringInfo();
     110           0 :         MemoryContextSwitchTo(oldcontext);
     111             : 
     112           0 :         startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
     113             :                                         dir, NULL, tblspc_map_file, false, true);
     114             : 
     115           0 :         before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
     116             :     }
     117             : 
     118           0 :     FreeDir(dir);
     119             : 
     120           0 :     PG_RETURN_LSN(startpoint);
     121             : }
     122             : 
     123             : /*
     124             :  * pg_stop_backup: finish taking an on-line backup dump
     125             :  *
     126             :  * We write an end-of-backup WAL record, and remove the backup label file
     127             :  * created by pg_start_backup, creating a backup history file in pg_wal
     128             :  * instead (whence it will immediately be archived). The backup history file
     129             :  * contains the same info found in the label file, plus the backup-end time
     130             :  * and WAL location. Before 9.0, the backup-end time was read from the backup
     131             :  * history file at the beginning of archive recovery, but we now use the WAL
     132             :  * record for that and the file is for informational and debug purposes only.
     133             :  *
     134             :  * Note: different from CancelBackup which just cancels online backup mode.
     135             :  *
     136             :  * Note: this version is only called to stop an exclusive backup. The function
     137             :  *       pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is called to
     138             :  *       stop non-exclusive backups.
     139             :  *
     140             :  * Permission checking for this function is managed through the normal
     141             :  * GRANT system.
     142             :  */
     143             : Datum
     144           0 : pg_stop_backup(PG_FUNCTION_ARGS)
     145             : {
     146             :     XLogRecPtr  stoppoint;
     147           0 :     SessionBackupState status = get_backup_status();
     148             : 
     149           0 :     if (status == SESSION_BACKUP_NON_EXCLUSIVE)
     150           0 :         ereport(ERROR,
     151             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     152             :                  errmsg("non-exclusive backup in progress"),
     153             :                  errhint("Did you mean to use pg_stop_backup('f')?")));
     154             : 
     155             :     /*
     156             :      * Exclusive backups were typically started in a different connection, so
     157             :      * don't try to verify that status of backup is set to
     158             :      * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that an
     159             :      * exclusive backup is in fact running is handled inside
     160             :      * do_pg_stop_backup.
     161             :      */
     162           0 :     stoppoint = do_pg_stop_backup(NULL, true, NULL);
     163             : 
     164           0 :     PG_RETURN_LSN(stoppoint);
     165             : }
     166             : 
     167             : 
     168             : /*
     169             :  * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
     170             :  *
     171             :  * Works the same as pg_stop_backup, except for non-exclusive backups it returns
     172             :  * the backup label and tablespace map files as text fields in as part of the
     173             :  * resultset.
     174             :  *
     175             :  * The first parameter (variable 'exclusive') allows the user to tell us if
     176             :  * this is an exclusive or a non-exclusive backup.
     177             :  *
     178             :  * The second parameter (variable 'waitforarchive'), which is optional,
     179             :  * allows the user to choose if they want to wait for the WAL to be archived
     180             :  * or if we should just return as soon as the WAL record is written.
     181             :  *
     182             :  * Permission checking for this function is managed through the normal
     183             :  * GRANT system.
     184             :  */
     185             : Datum
     186           0 : pg_stop_backup_v2(PG_FUNCTION_ARGS)
     187             : {
     188           0 :     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
     189             :     TupleDesc   tupdesc;
     190             :     Tuplestorestate *tupstore;
     191             :     MemoryContext per_query_ctx;
     192             :     MemoryContext oldcontext;
     193             :     Datum       values[3];
     194             :     bool        nulls[3];
     195             : 
     196           0 :     bool        exclusive = PG_GETARG_BOOL(0);
     197           0 :     bool        waitforarchive = PG_GETARG_BOOL(1);
     198             :     XLogRecPtr  stoppoint;
     199           0 :     SessionBackupState status = get_backup_status();
     200             : 
     201             :     /* check to see if caller supports us returning a tuplestore */
     202           0 :     if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
     203           0 :         ereport(ERROR,
     204             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     205             :                  errmsg("set-valued function called in context that cannot accept a set")));
     206           0 :     if (!(rsinfo->allowedModes & SFRM_Materialize))
     207           0 :         ereport(ERROR,
     208             :                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
     209             :                  errmsg("materialize mode required, but it is not " \
     210             :                         "allowed in this context")));
     211             : 
     212             :     /* Build a tuple descriptor for our result type */
     213           0 :     if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
     214           0 :         elog(ERROR, "return type must be a row type");
     215             : 
     216           0 :     per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
     217           0 :     oldcontext = MemoryContextSwitchTo(per_query_ctx);
     218             : 
     219           0 :     tupstore = tuplestore_begin_heap(true, false, work_mem);
     220           0 :     rsinfo->returnMode = SFRM_Materialize;
     221           0 :     rsinfo->setResult = tupstore;
     222           0 :     rsinfo->setDesc = tupdesc;
     223             : 
     224           0 :     MemoryContextSwitchTo(oldcontext);
     225             : 
     226           0 :     MemSet(values, 0, sizeof(values));
     227           0 :     MemSet(nulls, 0, sizeof(nulls));
     228             : 
     229           0 :     if (exclusive)
     230             :     {
     231           0 :         if (status == SESSION_BACKUP_NON_EXCLUSIVE)
     232           0 :             ereport(ERROR,
     233             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     234             :                      errmsg("non-exclusive backup in progress"),
     235             :                      errhint("Did you mean to use pg_stop_backup('f')?")));
     236             : 
     237             :         /*
     238             :          * Stop the exclusive backup, and since we're in an exclusive backup
     239             :          * return NULL for both backup_label and tablespace_map.
     240             :          */
     241           0 :         stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
     242             : 
     243           0 :         nulls[1] = true;
     244           0 :         nulls[2] = true;
     245             :     }
     246             :     else
     247             :     {
     248           0 :         if (status != SESSION_BACKUP_NON_EXCLUSIVE)
     249           0 :             ereport(ERROR,
     250             :                     (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     251             :                      errmsg("non-exclusive backup is not in progress"),
     252             :                      errhint("Did you mean to use pg_stop_backup('t')?")));
     253             : 
     254             :         /*
     255             :          * Stop the non-exclusive backup. Return a copy of the backup label
     256             :          * and tablespace map so they can be written to disk by the caller.
     257             :          */
     258           0 :         stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
     259           0 :         cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
     260             : 
     261           0 :         values[1] = CStringGetTextDatum(label_file->data);
     262           0 :         values[2] = CStringGetTextDatum(tblspc_map_file->data);
     263             : 
     264             :         /* Free structures allocated in TopMemoryContext */
     265           0 :         pfree(label_file->data);
     266           0 :         pfree(label_file);
     267           0 :         label_file = NULL;
     268           0 :         pfree(tblspc_map_file->data);
     269           0 :         pfree(tblspc_map_file);
     270           0 :         tblspc_map_file = NULL;
     271             :     }
     272             : 
     273             :     /* Stoppoint is included on both exclusive and nonexclusive backups */
     274           0 :     values[0] = LSNGetDatum(stoppoint);
     275             : 
     276           0 :     tuplestore_putvalues(tupstore, tupdesc, values, nulls);
     277             :     tuplestore_donestoring(typstore);
     278             : 
     279           0 :     return (Datum) 0;
     280             : }
     281             : 
     282             : /*
     283             :  * pg_switch_wal: switch to next xlog file
     284             :  *
     285             :  * Permission checking for this function is managed through the normal
     286             :  * GRANT system.
     287             :  */
     288             : Datum
     289           0 : pg_switch_wal(PG_FUNCTION_ARGS)
     290             : {
     291             :     XLogRecPtr  switchpoint;
     292             : 
     293           0 :     if (RecoveryInProgress())
     294           0 :         ereport(ERROR,
     295             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     296             :                  errmsg("recovery is in progress"),
     297             :                  errhint("WAL control functions cannot be executed during recovery.")));
     298             : 
     299           0 :     switchpoint = RequestXLogSwitch(false);
     300             : 
     301             :     /*
     302             :      * As a convenience, return the WAL location of the switch record
     303             :      */
     304           0 :     PG_RETURN_LSN(switchpoint);
     305             : }
     306             : 
     307             : /*
     308             :  * pg_create_restore_point: a named point for restore
     309             :  *
     310             :  * Permission checking for this function is managed through the normal
     311             :  * GRANT system.
     312             :  */
     313             : Datum
     314           0 : pg_create_restore_point(PG_FUNCTION_ARGS)
     315             : {
     316           0 :     text       *restore_name = PG_GETARG_TEXT_PP(0);
     317             :     char       *restore_name_str;
     318             :     XLogRecPtr  restorepoint;
     319             : 
     320           0 :     if (RecoveryInProgress())
     321           0 :         ereport(ERROR,
     322             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     323             :                  (errmsg("recovery is in progress"),
     324             :                   errhint("WAL control functions cannot be executed during recovery."))));
     325             : 
     326           0 :     if (!XLogIsNeeded())
     327           0 :         ereport(ERROR,
     328             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     329             :                  errmsg("WAL level not sufficient for creating a restore point"),
     330             :                  errhint("wal_level must be set to \"replica\" or \"logical\" at server start.")));
     331             : 
     332           0 :     restore_name_str = text_to_cstring(restore_name);
     333             : 
     334           0 :     if (strlen(restore_name_str) >= MAXFNAMELEN)
     335           0 :         ereport(ERROR,
     336             :                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
     337             :                  errmsg("value too long for restore point (maximum %d characters)", MAXFNAMELEN - 1)));
     338             : 
     339           0 :     restorepoint = XLogRestorePoint(restore_name_str);
     340             : 
     341             :     /*
     342             :      * As a convenience, return the WAL location of the restore point record
     343             :      */
     344           0 :     PG_RETURN_LSN(restorepoint);
     345             : }
     346             : 
     347             : /*
     348             :  * Report the current WAL write location (same format as pg_start_backup etc)
     349             :  *
     350             :  * This is useful for determining how much of WAL is visible to an external
     351             :  * archiving process.  Note that the data before this point is written out
     352             :  * to the kernel, but is not necessarily synced to disk.
     353             :  */
     354             : Datum
     355           0 : pg_current_wal_lsn(PG_FUNCTION_ARGS)
     356             : {
     357             :     XLogRecPtr  current_recptr;
     358             : 
     359           0 :     if (RecoveryInProgress())
     360           0 :         ereport(ERROR,
     361             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     362             :                  errmsg("recovery is in progress"),
     363             :                  errhint("WAL control functions cannot be executed during recovery.")));
     364             : 
     365           0 :     current_recptr = GetXLogWriteRecPtr();
     366             : 
     367           0 :     PG_RETURN_LSN(current_recptr);
     368             : }
     369             : 
     370             : /*
     371             :  * Report the current WAL insert location (same format as pg_start_backup etc)
     372             :  *
     373             :  * This function is mostly for debugging purposes.
     374             :  */
     375             : Datum
     376           0 : pg_current_wal_insert_lsn(PG_FUNCTION_ARGS)
     377             : {
     378             :     XLogRecPtr  current_recptr;
     379             : 
     380           0 :     if (RecoveryInProgress())
     381           0 :         ereport(ERROR,
     382             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     383             :                  errmsg("recovery is in progress"),
     384             :                  errhint("WAL control functions cannot be executed during recovery.")));
     385             : 
     386           0 :     current_recptr = GetXLogInsertRecPtr();
     387             : 
     388           0 :     PG_RETURN_LSN(current_recptr);
     389             : }
     390             : 
     391             : /*
     392             :  * Report the current WAL flush location (same format as pg_start_backup etc)
     393             :  *
     394             :  * This function is mostly for debugging purposes.
     395             :  */
     396             : Datum
     397           0 : pg_current_wal_flush_lsn(PG_FUNCTION_ARGS)
     398             : {
     399             :     XLogRecPtr  current_recptr;
     400             : 
     401           0 :     if (RecoveryInProgress())
     402           0 :         ereport(ERROR,
     403             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     404             :                  errmsg("recovery is in progress"),
     405             :                  errhint("WAL control functions cannot be executed during recovery.")));
     406             : 
     407           0 :     current_recptr = GetFlushRecPtr();
     408             : 
     409           0 :     PG_RETURN_LSN(current_recptr);
     410             : }
     411             : 
     412             : /*
     413             :  * Report the last WAL receive location (same format as pg_start_backup etc)
     414             :  *
     415             :  * This is useful for determining how much of WAL is guaranteed to be received
     416             :  * and synced to disk by walreceiver.
     417             :  */
     418             : Datum
     419           0 : pg_last_wal_receive_lsn(PG_FUNCTION_ARGS)
     420             : {
     421             :     XLogRecPtr  recptr;
     422             : 
     423           0 :     recptr = GetWalRcvWriteRecPtr(NULL, NULL);
     424             : 
     425           0 :     if (recptr == 0)
     426           0 :         PG_RETURN_NULL();
     427             : 
     428           0 :     PG_RETURN_LSN(recptr);
     429             : }
     430             : 
     431             : /*
     432             :  * Report the last WAL replay location (same format as pg_start_backup etc)
     433             :  *
     434             :  * This is useful for determining how much of WAL is visible to read-only
     435             :  * connections during recovery.
     436             :  */
     437             : Datum
     438           0 : pg_last_wal_replay_lsn(PG_FUNCTION_ARGS)
     439             : {
     440             :     XLogRecPtr  recptr;
     441             : 
     442           0 :     recptr = GetXLogReplayRecPtr(NULL);
     443             : 
     444           0 :     if (recptr == 0)
     445           0 :         PG_RETURN_NULL();
     446             : 
     447           0 :     PG_RETURN_LSN(recptr);
     448             : }
     449             : 
     450             : /*
     451             :  * Compute an xlog file name and decimal byte offset given a WAL location,
     452             :  * such as is returned by pg_stop_backup() or pg_switch_wal().
     453             :  *
     454             :  * Note that a location exactly at a segment boundary is taken to be in
     455             :  * the previous segment.  This is usually the right thing, since the
     456             :  * expected usage is to determine which xlog file(s) are ready to archive.
     457             :  */
     458             : Datum
     459           0 : pg_walfile_name_offset(PG_FUNCTION_ARGS)
     460             : {
     461             :     XLogSegNo   xlogsegno;
     462             :     uint32      xrecoff;
     463           0 :     XLogRecPtr  locationpoint = PG_GETARG_LSN(0);
     464             :     char        xlogfilename[MAXFNAMELEN];
     465             :     Datum       values[2];
     466             :     bool        isnull[2];
     467             :     TupleDesc   resultTupleDesc;
     468             :     HeapTuple   resultHeapTuple;
     469             :     Datum       result;
     470             : 
     471           0 :     if (RecoveryInProgress())
     472           0 :         ereport(ERROR,
     473             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     474             :                  errmsg("recovery is in progress"),
     475             :                  errhint("pg_walfile_name_offset() cannot be executed during recovery.")));
     476             : 
     477             :     /*
     478             :      * Construct a tuple descriptor for the result row.  This must match this
     479             :      * function's pg_proc entry!
     480             :      */
     481           0 :     resultTupleDesc = CreateTemplateTupleDesc(2, false);
     482           0 :     TupleDescInitEntry(resultTupleDesc, (AttrNumber) 1, "file_name",
     483             :                        TEXTOID, -1, 0);
     484           0 :     TupleDescInitEntry(resultTupleDesc, (AttrNumber) 2, "file_offset",
     485             :                        INT4OID, -1, 0);
     486             : 
     487           0 :     resultTupleDesc = BlessTupleDesc(resultTupleDesc);
     488             : 
     489             :     /*
     490             :      * xlogfilename
     491             :      */
     492           0 :     XLByteToPrevSeg(locationpoint, xlogsegno);
     493           0 :     XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
     494             : 
     495           0 :     values[0] = CStringGetTextDatum(xlogfilename);
     496           0 :     isnull[0] = false;
     497             : 
     498             :     /*
     499             :      * offset
     500             :      */
     501           0 :     xrecoff = locationpoint % XLogSegSize;
     502             : 
     503           0 :     values[1] = UInt32GetDatum(xrecoff);
     504           0 :     isnull[1] = false;
     505             : 
     506             :     /*
     507             :      * Tuple jam: Having first prepared your Datums, then squash together
     508             :      */
     509           0 :     resultHeapTuple = heap_form_tuple(resultTupleDesc, values, isnull);
     510             : 
     511           0 :     result = HeapTupleGetDatum(resultHeapTuple);
     512             : 
     513           0 :     PG_RETURN_DATUM(result);
     514             : }
     515             : 
     516             : /*
     517             :  * Compute an xlog file name given a WAL location,
     518             :  * such as is returned by pg_stop_backup() or pg_switch_wal().
     519             :  */
     520             : Datum
     521           0 : pg_walfile_name(PG_FUNCTION_ARGS)
     522             : {
     523             :     XLogSegNo   xlogsegno;
     524           0 :     XLogRecPtr  locationpoint = PG_GETARG_LSN(0);
     525             :     char        xlogfilename[MAXFNAMELEN];
     526             : 
     527           0 :     if (RecoveryInProgress())
     528           0 :         ereport(ERROR,
     529             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     530             :                  errmsg("recovery is in progress"),
     531             :                  errhint("pg_walfile_name() cannot be executed during recovery.")));
     532             : 
     533           0 :     XLByteToPrevSeg(locationpoint, xlogsegno);
     534           0 :     XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno);
     535             : 
     536           0 :     PG_RETURN_TEXT_P(cstring_to_text(xlogfilename));
     537             : }
     538             : 
     539             : /*
     540             :  * pg_wal_replay_pause - pause recovery now
     541             :  *
     542             :  * Permission checking for this function is managed through the normal
     543             :  * GRANT system.
     544             :  */
     545             : Datum
     546           0 : pg_wal_replay_pause(PG_FUNCTION_ARGS)
     547             : {
     548           0 :     if (!RecoveryInProgress())
     549           0 :         ereport(ERROR,
     550             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     551             :                  errmsg("recovery is not in progress"),
     552             :                  errhint("Recovery control functions can only be executed during recovery.")));
     553             : 
     554           0 :     SetRecoveryPause(true);
     555             : 
     556           0 :     PG_RETURN_VOID();
     557             : }
     558             : 
     559             : /*
     560             :  * pg_wal_replay_resume - resume recovery now
     561             :  *
     562             :  * Permission checking for this function is managed through the normal
     563             :  * GRANT system.
     564             :  */
     565             : Datum
     566           0 : pg_wal_replay_resume(PG_FUNCTION_ARGS)
     567             : {
     568           0 :     if (!RecoveryInProgress())
     569           0 :         ereport(ERROR,
     570             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     571             :                  errmsg("recovery is not in progress"),
     572             :                  errhint("Recovery control functions can only be executed during recovery.")));
     573             : 
     574           0 :     SetRecoveryPause(false);
     575             : 
     576           0 :     PG_RETURN_VOID();
     577             : }
     578             : 
     579             : /*
     580             :  * pg_is_wal_replay_paused
     581             :  */
     582             : Datum
     583           0 : pg_is_wal_replay_paused(PG_FUNCTION_ARGS)
     584             : {
     585           0 :     if (!RecoveryInProgress())
     586           0 :         ereport(ERROR,
     587             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     588             :                  errmsg("recovery is not in progress"),
     589             :                  errhint("Recovery control functions can only be executed during recovery.")));
     590             : 
     591           0 :     PG_RETURN_BOOL(RecoveryIsPaused());
     592             : }
     593             : 
     594             : /*
     595             :  * Returns timestamp of latest processed commit/abort record.
     596             :  *
     597             :  * When the server has been started normally without recovery the function
     598             :  * returns NULL.
     599             :  */
     600             : Datum
     601           0 : pg_last_xact_replay_timestamp(PG_FUNCTION_ARGS)
     602             : {
     603             :     TimestampTz xtime;
     604             : 
     605           0 :     xtime = GetLatestXTime();
     606           0 :     if (xtime == 0)
     607           0 :         PG_RETURN_NULL();
     608             : 
     609           0 :     PG_RETURN_TIMESTAMPTZ(xtime);
     610             : }
     611             : 
     612             : /*
     613             :  * Returns bool with current recovery mode, a global state.
     614             :  */
     615             : Datum
     616           0 : pg_is_in_recovery(PG_FUNCTION_ARGS)
     617             : {
     618           0 :     PG_RETURN_BOOL(RecoveryInProgress());
     619             : }
     620             : 
     621             : /*
     622             :  * Compute the difference in bytes between two WAL locations.
     623             :  */
     624             : Datum
     625           0 : pg_wal_lsn_diff(PG_FUNCTION_ARGS)
     626             : {
     627             :     Datum       result;
     628             : 
     629           0 :     result = DirectFunctionCall2(pg_lsn_mi,
     630             :                                  PG_GETARG_DATUM(0),
     631             :                                  PG_GETARG_DATUM(1));
     632             : 
     633           0 :     PG_RETURN_NUMERIC(result);
     634             : }
     635             : 
     636             : /*
     637             :  * Returns bool with current on-line backup mode, a global state.
     638             :  */
     639             : Datum
     640           0 : pg_is_in_backup(PG_FUNCTION_ARGS)
     641             : {
     642           0 :     PG_RETURN_BOOL(BackupInProgress());
     643             : }
     644             : 
     645             : /*
     646             :  * Returns start time of an online exclusive backup.
     647             :  *
     648             :  * When there's no exclusive backup in progress, the function
     649             :  * returns NULL.
     650             :  */
     651             : Datum
     652           0 : pg_backup_start_time(PG_FUNCTION_ARGS)
     653             : {
     654             :     Datum       xtime;
     655             :     FILE       *lfp;
     656             :     char        fline[MAXPGPATH];
     657             :     char        backup_start_time[30];
     658             : 
     659             :     /*
     660             :      * See if label file is present
     661             :      */
     662           0 :     lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
     663           0 :     if (lfp == NULL)
     664             :     {
     665           0 :         if (errno != ENOENT)
     666           0 :             ereport(ERROR,
     667             :                     (errcode_for_file_access(),
     668             :                      errmsg("could not read file \"%s\": %m",
     669             :                             BACKUP_LABEL_FILE)));
     670           0 :         PG_RETURN_NULL();
     671             :     }
     672             : 
     673             :     /*
     674             :      * Parse the file to find the START TIME line.
     675             :      */
     676           0 :     backup_start_time[0] = '\0';
     677           0 :     while (fgets(fline, sizeof(fline), lfp) != NULL)
     678             :     {
     679           0 :         if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) == 1)
     680           0 :             break;
     681             :     }
     682             : 
     683             :     /* Check for a read error. */
     684           0 :     if (ferror(lfp))
     685           0 :         ereport(ERROR,
     686             :                 (errcode_for_file_access(),
     687             :                  errmsg("could not read file \"%s\": %m", BACKUP_LABEL_FILE)));
     688             : 
     689             :     /* Close the backup label file. */
     690           0 :     if (FreeFile(lfp))
     691           0 :         ereport(ERROR,
     692             :                 (errcode_for_file_access(),
     693             :                  errmsg("could not close file \"%s\": %m", BACKUP_LABEL_FILE)));
     694             : 
     695           0 :     if (strlen(backup_start_time) == 0)
     696           0 :         ereport(ERROR,
     697             :                 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
     698             :                  errmsg("invalid data in file \"%s\"", BACKUP_LABEL_FILE)));
     699             : 
     700             :     /*
     701             :      * Convert the time string read from file to TimestampTz form.
     702             :      */
     703           0 :     xtime = DirectFunctionCall3(timestamptz_in,
     704             :                                 CStringGetDatum(backup_start_time),
     705             :                                 ObjectIdGetDatum(InvalidOid),
     706             :                                 Int32GetDatum(-1));
     707             : 
     708           0 :     PG_RETURN_DATUM(xtime);
     709             : }

Generated by: LCOV version 1.11