Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x8XxR-00000001K3g-13MA for pgsql-hackers@arkaria.postgresql.org; Mon, 21 Sep 2026 06:56:57 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.98.2) (envelope-from ) id 1x8XxQ-000000082yK-2IZL for pgsql-hackers@arkaria.postgresql.org; Mon, 21 Sep 2026 06:56:56 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x8XxP-000000082yB-4BeP for pgsql-hackers@lists.postgresql.org; Mon, 21 Sep 2026 06:56:56 +0000 Received: from mail-pj2-x11.google.com ([2607:f8b0:4864:39::11]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1x8XxM-00000000S3e-3b12 for pgsql-hackers@lists.postgresql.org; Mon, 21 Sep 2026 06:56:54 +0000 Received: by mail-pj2-x11.google.com with SMTP id 98e67ed59e1d1-39b350c69b4so2295268a91.2 for ; Sun, 20 Sep 2026 23:56:53 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1789973812; x=1790578612; darn=lists.postgresql.org; h=references:to:cc:in-reply-to:date:subject:mime-version:content-type :message-id:from:from:to:cc:subject:date:message-id:reply-to :content-type; bh=M1iYSz7xFkQWpxFw91OrJZ98q60JiKoLg2mF5UM7/tY=; b=ljGqUhUoFHM3CD5goDOp+WfjEleRQ8/czVqRcy4GtIxftzWZVk5Yro2F69PG5MOWED T9IggBnY5WRiWJ3OExa2dyM/i7KtIfL1+q4GEM5EYUAc2nRBoJFMqaaB11n0nDfW1DKH aTL30YZrVz7rnGhj3s1XVK3XnRBuZMK0+fps9NKwOJFriM9wYFBZEdcsONr4A77Oll1S qKW1f2VvS1yzZlT7IZ66IneGg6BP+dqVylVvWCKsKYi6zqod3Vhwf0si71ldXgdd498+ zDVieDiPagCoDa/3CZU0iWcgHoUuGNA/jrwCH/X+rxewBOkpmOlV4ZqPgH18ntb3sHlG tWcQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20260707; t=1789973812; x=1790578612; h=references:to:cc:in-reply-to:date:subject:mime-version:content-type :message-id:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=M1iYSz7xFkQWpxFw91OrJZ98q60JiKoLg2mF5UM7/tY=; b=L3O0EaGvYKgMCCtx27P9o3WBqhn/xAPO3urK8taRUYpbWREDNFeu2a6N8X983A71pM 0hE6OnIDUU8b2xztXWJ2d7Rr0YBtT9H4FC0Wyaw95FdkosmszTU/0acMUfSV5nLCHpM2 zXY1DF9Qax3r0I1iMRMEWbt2AiBxLAOeJyQuo/T4FKIv9WOttlGrhnxK87Atf5DQKBtR pMbTEAV2iUrPnkDso2ASpyAs7JbyJ/MoW7SAS88g9+RKBtQZWYlvZfVmJZxeJ1gW/4Zb 0H/8J0pLsOuKmnjM4LYmRnYyWgLIj2Zh1heA1LDwSuSztm6Z/c5wt6tGAb1q4G3Lf+fD NeqA== X-Gm-Message-State: AFuF++n22ZtDGWTHIrKrRqodRcMDvFOwYrMAYWIUeTmRWZmkYfIP8s9E l1T+ozzwW/SURfZvuBr44MMVXNcsUrJ1QwR6Y/M3O1+ArLiQMQb3lK2G X-Gm-Gg: AYBFou2qlaeEpG/iHbCvCWtvDLe103DlgPcmR4lXxr8ZR2WvjsxCMlKerVLUdvDWDEJ 9lVnBCi97kAT7/CNA/YZBUMsxbd6UIYbDqz6Loj1PnCCvHnoY4Rzwawagga+IzFsRTsXRRXNf32 k7rzAaIV1KQ5ulzhlavzlJLMBpMvVxO6nYmivPYNZIXew6SXYvjlWSAd4bD0I4CyhUd2bzt9FxT k5Ovo3Qit0/vRdJzO6Td2kZHtILcbn4y0xfZaogssW0DSi6Mgc4jTNI1aZRi61wsfrPgj22Xl3z V1SMfhPHycAuiNSX/aXDe14aE8Pnc5L0kre+sG+ytfKUY37d8KVY6HqTbNf+ZBSrNHol+PKXP3e 0RAPTGZk8hXo0qt9SsxrQvagQMMKD5PeTgJmX9bnskfiv1a3TCk11Fccx4OQ+H2khR36fvlsEOL x0SWBKdVREHc+0b6OIVFyu2KCUX26L3OeqEDGD+lu8cfBc4Zi9mnbObZdFGjG3GLUII+tXElf0m Fueo405 X-Received: by 2002:a17:90a:d64f:b0:39e:4c80:44b9 with SMTP id 98e67ed59e1d1-39e54dccbb8mr16198893a91.28.1789973812397; Sun, 20 Sep 2026 23:56:52 -0700 (PDT) Received: from smtpclient.apple ([185.135.79.161]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-39e6cabb771sm12786566a91.9.2026.09.20.23.56.49 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Sun, 20 Sep 2026 23:56:51 -0700 (PDT) From: Chao Li Message-Id: <8949F1E9-C296-47B4-ADC0-C5276388DB10@gmail.com> Content-Type: multipart/mixed; boundary="Apple-Mail=_E13A3BC8-B1B7-4478-A932-3C8AAFC19B37" Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3864.700.51.1.1\)) Subject: Re: pg_walinspect: fix LSN validation messages and empty range handling Date: Mon, 21 Sep 2026 14:56:16 +0800 In-Reply-To: Cc: PostgreSQL Hackers , Bharath Rupireddy To: Kiran Kaki References: <7B8F5F12-98A5-4618-867A-904EA1334FD4@gmail.com> X-Mailer: Apple Mail (2.3864.700.51.1.1) List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk --Apple-Mail=_E13A3BC8-B1B7-4478-A932-3C8AAFC19B37 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 > On Sep 21, 2026, at 02:40, Kiran Kaki wrote: >=20 > Hi Chao >=20 > On Sat, Sep 19, 2026 at 8:08=E2=80=AFPM Chao Li = wrote: >>=20 >> Hi, >>=20 >> While working on patch [1], I noticed two small issues with = pg_walinspect. >>=20 >> 1. In pg_get_wal_record_info() as well as a few other functions, = there are checks like: >> ``` >> if (lsn > curr_lsn) >> ereport(ERROR, >> = (errcode(ERRCODE_INVALID_PARAMETER_VALUE), >> errmsg("WAL input LSN must be less = than current LSN"), >> errdetail("Current WAL LSN on the = database system is at %X/%08X.", >> = LSN_FORMAT_ARGS(curr_lsn)))); >> ``` >>=20 >> The check itself uses a > comparison, so equality is accepted by this = validation check. However, the error message says "must be less than", = which implies that equality is not accepted. Thus, the check and the = error message are inconsistent. >>=20 >> Commit 5c1b6628075a changed the check from >=3D to > and changed the = error message from "cannot accept future input LSN" to "WAL input LSN = must be less than current LSN". This seems to have been an oversight. >>=20 >> The error message can be changed to say "must be less than or equal = to", matching the actual validation condition. >=20 > Thanks for the patch. 0001 looks good to me. Thank you very much for the review. >=20 > As I see 5c1b6628075a relaxed these checks from >=3D to > but left the = messages > saying "less than", so the wording no longer matches the code. I > checked the thread behind that commit to confirm accepting equality > was deliberate. >=20 > Tested on master (9e17d25e79d4): >=20 > - Applies cleanly, builds with no new warnings > - pg_walinspect/regress passes, and so does the full suite > - Expected-output changes match the new messages exactly > - No other LSN validation message has the same problem >=20 > Also, the existing tests already cover every message that changed. >=20 >=20 >> 2. pg_get_wal_records_info() accepts an end_lsn equal to start_lsn, = but the same fixed range can produce different results. For example: >> ``` >> evantest=3D# select pg_current_wal_flush_lsn(); >> pg_current_wal_flush_lsn >> -------------------------- >> 0/01D61428 >> (1 row) >> evantest=3D# SELECT * FROM pg_get_wal_records_info('0/01D61428', = '0/01D61428'); >> ERROR: could not find a valid record after 0/01D61428 >>=20 >> evantest=3D# checkpoint; >> CHECKPOINT >> evantest=3D# SELECT * FROM pg_get_wal_records_info('0/01D61428', = '0/01D61428'); >> start_lsn | end_lsn | prev_lsn | xid | resource_manager | record_type = | record_length | main_data_length | fpi_length | description | = block_ref >> = -----------+---------+----------+-----+------------------+-------------+--= -------------+------------------+------------+-------------+----------- >> (0 rows) >> ``` >>=20 >> When I passed the current flushed LSN to pg_get_wal_records_info() as = both start_lsn and end_lsn, it raised an error because no record was = available at or after that LSN. After I ran CHECKPOINT to generate more = WAL records, the same query returned zero rows. >>=20 >> Thus, the same fixed range can either raise an error or return zero = rows depending on whether WAL exists after end_lsn, even though WAL = after end_lsn cannot belong to the requested range. This may confuse = users. >>=20 >> To fix, I think an empty LSN range cannot contain a complete WAL = record, so it can be handled without initializing a WAL reader. So that, = the record and block information functions can return zero rows, while = pg_get_wal_stats() can preserve its zero-valued aggregate output. >>=20 >> [1] = https://www.postgresql.org/message-id/80E9F0AD-CFC5-4BE5-81DE-D8FE35E10A1C= %40gmail.com >=20 > 0002 looks right to me with two suggestions >=20 > I reproduced the problem on an unpatched build: an empty range at the > end of WAL errors with "could not find a valid record after * ", > while the same empty range mid-WAL returns 0 rows. So the result > depends on whether anything wrote WAL afterwards, which is worth > fixing. >=20 > Tested on master (9e17d25e79d4): >=20 > - Applies cleanly on top of 0001, builds with no new warnings > - pg_walinspect/regress passes, and so does the full suite > - Empty ranges now return 0 rows instead of erroring; > - Non-empty ranges are unaffected >=20 > Two small things: >=20 > 1. Minor: In GetWalStats() the "An empty range cannot contain any WAL > records" comment sits above "if (start_lsn < end_lsn)", the > opposite sense from the other two sites. The structure has to > differ there since it still calls GetXLogSummaryStats(), but the > comment reads the wrong way round. Maybe "Read records only if the > range is non-empty." Accepted. >=20 > 2. One thing: pg_get_wal_record_info() isn't covered. Passing it the > current LSN still errors in the reader. Same "validation accepts it, > then the reader fails" shape, though the right answer is less clear > there: it returns a single row rather than a set, so returning nothing > isn't an option, and the error isn't inaccurate. I think it would be = worth > handling alongside this, if you agree the shape is the same.. >=20 I don=E2=80=99t think we should change pg_get_wal_record_info(). Its doc = says: ``` If in_lsn isn't at the start of a WAL record, information about the next valid WAL record is shown instead. If there is no next valid WAL record, the function raises an error. ``` The doc predates 5c1b6628075a, so I don=E2=80=99t think we should change = the doc behavior. However, your comment led me to notice that the documentation for = pg_get_wal_records_info() says: ``` The function raises an error if start_lsn is not available. ``` This makes the issue trickier. Before 5c1b6628075a, start_lsn had to be = less than end_lsn, so an empty range was not accepted and this = inconsistency could not arise. Based on the current doc, however, it = seems reasonable for start_lsn =3D=3D end_lsn to return zero rows when = start_lsn is available and raise an error when it is not. =46rom this perspective, I think I should withdraw 0002. PFA v2: * 0001 is unchanged=20 * Withdraw 0002 Best regards, -- Chao Li (Evan) HighGo Software Co., Ltd. https://www.highgo.com/ --Apple-Mail=_E13A3BC8-B1B7-4478-A932-3C8AAFC19B37 Content-Disposition: attachment; filename=v2-0001-Fix-inaccurate-LSN-validation-messages-in-pg_wali.patch Content-Type: application/octet-stream; x-unix-mode=0644; name="v2-0001-Fix-inaccurate-LSN-validation-messages-in-pg_wali.patch" Content-Transfer-Encoding: quoted-printable =46rom=20d64d6f49e8935b4bde52510c02307c201fba8f6a=20Mon=20Sep=2017=20= 00:00:00=202001=0AFrom:=20"Chao=20Li=20(Evan)"=20=0A= Date:=20Sun,=2020=20Sep=202026=2009:39:56=20+0800=0ASubject:=20[PATCH=20= v2]=20Fix=20inaccurate=20LSN=20validation=20messages=20in=20= pg_walinspect=0A=0ACommit=205c1b6628075a=20changed=20the=20LSN=20= validation=20checks=20to=20allow=20an=20input=0ALSN=20to=20equal=20the=20= current=20LSN=20and=20a=20start=20LSN=20to=20equal=20the=20end=20LSN.=0A= However,=20the=20corresponding=20error=20messages=20continued=20to=20say=20= that=20the=0ALSNs=20had=20to=20be=20less=20than=20those=20bounds.=0A=0A= This=20was=20an=20oversight=20in=205c1b6628.=20=20Adjust=20the=20= messages=20to=20say=20"less=0Athan=20or=20equal=20to",=20matching=20the=20= actual=20validation=20conditions.=0A=0AAuthor:=20Chao=20Li=20= =0AReviewed-by:=20Kiran=20Kaki=20=0A= Discussion:=20= https://postgr.es/m/7B8F5F12-98A5-4618-867A-904EA1334FD4@gmail.com=0A---=0A= =20contrib/pg_walinspect/expected/oldextversions.out=20|=20=204=20++--=0A= =20contrib/pg_walinspect/expected/pg_walinspect.out=20=20|=2014=20= +++++++-------=0A=20contrib/pg_walinspect/pg_walinspect.c=20=20=20=20=20=20= =20=20=20=20=20=20=20|=2010=20+++++-----=0A=203=20files=20changed,=2014=20= insertions(+),=2014=20deletions(-)=0A=0Adiff=20--git=20= a/contrib/pg_walinspect/expected/oldextversions.out=20= b/contrib/pg_walinspect/expected/oldextversions.out=0Aindex=20= 89953af3d0e..fd65ed149c6=20100644=0A---=20= a/contrib/pg_walinspect/expected/oldextversions.out=0A+++=20= b/contrib/pg_walinspect/expected/oldextversions.out=0A@@=20-43,9=20+43,9=20= @@=20SELECT=20COUNT(*)=20>=3D=201=20AS=20ok=20FROM=20= pg_get_wal_stats_till_end_of_wal(:'wal_lsn1');=0A=20=0A=20--=20Failures=20= with=20start=20LSNs.=0A=20SELECT=20*=20FROM=20= pg_get_wal_records_info_till_end_of_wal('FFFFFFFF/FFFFFFFF');=0A-ERROR:=20= =20WAL=20start=20LSN=20must=20be=20less=20than=20current=20LSN=0A+ERROR:=20= =20WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN=0A=20SELECT=20*=20FROM=20= pg_get_wal_stats_till_end_of_wal('FFFFFFFF/FFFFFFFF');=0A-ERROR:=20=20= WAL=20start=20LSN=20must=20be=20less=20than=20current=20LSN=0A+ERROR:=20=20= WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20current=20= LSN=0A=20--=20Move=20to=20new=20version=201.1.=0A=20ALTER=20EXTENSION=20= pg_walinspect=20UPDATE=20TO=20'1.1';=0A=20--=20List=20what=20version=20= 1.1=20contains.=0Adiff=20--git=20= a/contrib/pg_walinspect/expected/pg_walinspect.out=20= b/contrib/pg_walinspect/expected/pg_walinspect.out=0Aindex=20= f955ff5d3c5..b9abeeebdfd=20100644=0A---=20= a/contrib/pg_walinspect/expected/pg_walinspect.out=0A+++=20= b/contrib/pg_walinspect/expected/pg_walinspect.out=0A@@=20-29,14=20= +29,14=20@@=20SELECT=20*=20FROM=20pg_get_wal_block_info('0/0',=20= :'wal_lsn1');=0A=20ERROR:=20=20could=20not=20read=20WAL=20at=20LSN=20= 0/00000000=0A=20--=20Start=20LSN=20>=20End=20LSN.=0A=20SELECT=20*=20FROM=20= pg_get_wal_records_info(:'wal_lsn2',=20:'wal_lsn1');=0A-ERROR:=20=20WAL=20= start=20LSN=20must=20be=20less=20than=20end=20LSN=0A+ERROR:=20=20WAL=20= start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20end=20LSN=0A=20= SELECT=20*=20FROM=20pg_get_wal_stats(:'wal_lsn2',=20:'wal_lsn1');=0A= -ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20end=20LSN=0A= +ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20= to=20end=20LSN=0A=20SELECT=20*=20FROM=20= pg_get_wal_block_info(:'wal_lsn2',=20:'wal_lsn1');=0A-ERROR:=20=20WAL=20= start=20LSN=20must=20be=20less=20than=20end=20LSN=0A+ERROR:=20=20WAL=20= start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20end=20LSN=0A=20= --=20LSNs=20with=20the=20highest=20value=20possible.=0A=20SELECT=20*=20= FROM=20pg_get_wal_record_info('FFFFFFFF/FFFFFFFF');=0A-ERROR:=20=20WAL=20= input=20LSN=20must=20be=20less=20than=20current=20LSN=0A+ERROR:=20=20WAL=20= input=20LSN=20must=20be=20less=20than=20or=20equal=20to=20current=20LSN=0A= =20--=20Success=20with=20end=20LSNs.=0A=20SELECT=20COUNT(*)=20>=3D=201=20= AS=20ok=20FROM=20pg_get_wal_records_info(:'wal_lsn1',=20= 'FFFFFFFF/FFFFFFFF');=0A=20=20ok=20=0A@@=20-58,11=20+58,11=20@@=20SELECT=20= COUNT(*)=20>=3D=201=20AS=20ok=20FROM=20= pg_get_wal_block_info(:'wal_lsn1',=20'FFFFFFFF/FFF=0A=20=0A=20--=20= Failures=20with=20start=20LSNs.=0A=20SELECT=20*=20FROM=20= pg_get_wal_records_info('FFFFFFFF/FFFFFFFE',=20'FFFFFFFF/FFFFFFFF');=0A= -ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20current=20LSN=0A= +ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20= to=20current=20LSN=0A=20SELECT=20*=20FROM=20= pg_get_wal_stats('FFFFFFFF/FFFFFFFE',=20'FFFFFFFF/FFFFFFFF');=0A-ERROR:=20= =20WAL=20start=20LSN=20must=20be=20less=20than=20current=20LSN=0A+ERROR:=20= =20WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN=0A=20SELECT=20*=20FROM=20= pg_get_wal_block_info('FFFFFFFF/FFFFFFFE',=20'FFFFFFFF/FFFFFFFF');=0A= -ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20current=20LSN=0A= +ERROR:=20=20WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20= to=20current=20LSN=0A=20--=20= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=20--=20Tests=20= for=20all=20function=20executions=0A=20--=20= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0Adiff=20--git=20= a/contrib/pg_walinspect/pg_walinspect.c=20= b/contrib/pg_walinspect/pg_walinspect.c=0Aindex=20= a172f9e2b40..6edd6f8cb35=20100644=0A---=20= a/contrib/pg_walinspect/pg_walinspect.c=0A+++=20= b/contrib/pg_walinspect/pg_walinspect.c=0A@@=20-488,7=20+488,7=20@@=20= pg_get_wal_record_info(PG_FUNCTION_ARGS)=0A=20=09if=20(lsn=20>=20= curr_lsn)=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A-=09=09=09=09=20errmsg("WAL=20= input=20LSN=20must=20be=20less=20than=20current=20LSN"),=0A+=09=09=09=09=20= errmsg("WAL=20input=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN"),=0A=20=09=09=09=09=20errdetail("Current=20WAL=20LSN=20on=20= the=20database=20system=20is=20at=20%X/%08X.",=0A=20=09=09=09=09=09=09=20= =20=20LSN_FORMAT_ARGS(curr_lsn))));=0A=20=0A@@=20-530,14=20+530,14=20@@=20= ValidateInputLSNs(XLogRecPtr=20start_lsn,=20XLogRecPtr=20*end_lsn)=0A=20=09= if=20(start_lsn=20>=20curr_lsn)=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A-=09=09=09=09=20errmsg("WAL=20= start=20LSN=20must=20be=20less=20than=20current=20LSN"),=0A+=09=09=09=09=20= errmsg("WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN"),=0A=20=09=09=09=09=20errdetail("Current=20WAL=20LSN=20on=20= the=20database=20system=20is=20at=20%X/%08X.",=0A=20=09=09=09=09=09=09=20= =20=20LSN_FORMAT_ARGS(curr_lsn))));=0A=20=0A=20=09if=20(start_lsn=20>=20= *end_lsn)=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A-=09=09=09=09=20errmsg("WAL=20= start=20LSN=20must=20be=20less=20than=20end=20LSN")));=0A+=09=09=09=09=20= errmsg("WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= end=20LSN")));=0A=20=0A=20=09if=20(*end_lsn=20>=20curr_lsn)=0A=20=09=09= *end_lsn=20=3D=20curr_lsn;=0A@@=20-836,7=20+836,7=20@@=20= pg_get_wal_records_info_till_end_of_wal(PG_FUNCTION_ARGS)=0A=20=09if=20= (start_lsn=20>=20end_lsn)=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A-=09=09=09=09=20errmsg("WAL=20= start=20LSN=20must=20be=20less=20than=20current=20LSN"),=0A+=09=09=09=09=20= errmsg("WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN"),=0A=20=09=09=09=09=20errdetail("Current=20WAL=20LSN=20on=20= the=20database=20system=20is=20at=20%X/%08X.",=0A=20=09=09=09=09=09=09=20= =20=20LSN_FORMAT_ARGS(end_lsn))));=0A=20=0A@@=20-855,7=20+855,7=20@@=20= pg_get_wal_stats_till_end_of_wal(PG_FUNCTION_ARGS)=0A=20=09if=20= (start_lsn=20>=20end_lsn)=0A=20=09=09ereport(ERROR,=0A=20=09=09=09=09= (errcode(ERRCODE_INVALID_PARAMETER_VALUE),=0A-=09=09=09=09=20errmsg("WAL=20= start=20LSN=20must=20be=20less=20than=20current=20LSN"),=0A+=09=09=09=09=20= errmsg("WAL=20start=20LSN=20must=20be=20less=20than=20or=20equal=20to=20= current=20LSN"),=0A=20=09=09=09=09=20errdetail("Current=20WAL=20LSN=20on=20= the=20database=20system=20is=20at=20%X/%08X.",=0A=20=09=09=09=09=09=09=20= =20=20LSN_FORMAT_ARGS(end_lsn))));=0A=20=0A--=20=0A2.50.1=20(Apple=20= Git-155)=0A=0A= --Apple-Mail=_E13A3BC8-B1B7-4478-A932-3C8AAFC19B37--