8000 Fix bug in nbtree array primitive scan scheduling. · postgres/postgres@763d65a · GitHub
[go: up one dir, main page]

Skip to content
{"payload":{"commit":{"oid":"763d65ae254569e0bdbe2cbb27b184112765f24f","url":"/postgres/postgres/commit/763d65ae254569e0bdbe2cbb27b184112765f24f","authoredDate":"2024-10-30T10:57:19.000-04:00","committedDate":"2024-10-30T10:57:19.000-04:00","shortMessage":null,"shortMessageMarkdown":"\u003cdiv\u003eFix bug in nbtree array primitive scan scheduling.\u003c/div\u003e","shortMessageMarkdownLink":null,"bodyMessageHtml":"A bug in nbtree's handling of primitive index scan scheduling could lead\nto wrong answers when a scrollable cursor was used with an index scan\nthat had a SAOP index qual. Wrong answers were only possible when the\nscan direction changed after a primitive scan was scheduled, but before\n_bt_next was asked to fetch the next tuple in line (i.e. for things to\nbreak, _bt_next had to be denied the opportunity to step off the page in\nthe same direction as the one used when the primscan was scheduled).\nFurthermore, the issue only occurred when the page in question happened\nto be the first page to be visited by the entire top-level scan; the\nissue hinged upon the cursor backing up to the absolute beginning of the\nkey space that it returns tuples from (fetching in the opposite scan\ndirection across a \"primitive scan boundary\" always worked correctly).\n\nTo fix, make _bt_next unset the \"needs primitive index scan\" flag when\nit detects that the current scan direction is not the one that was used\nby _bt_readpage back when the primitive scan in question was scheduled.\nThis fixes the cases that are known to be faulty, and also seems like a\ngood idea on general robustness grounds.\n\nAffected scrollable cursor cases now avoid a spurious primitive index\nscan when they fetch backwards to the absolute start of the key space to\nbe visited by their cursor. Fetching backwards now only returns those\ntuples at the start of the scan, as expected. It'll also be okay to\nonce again fetch forwards from the start at that point, since the scan\nwill be left in a state that's exactly consistent with the state it was\nin before any tuples were ever fetched, as expected.\n\nOversight in commit \u003ca class=\"commit-link\" data-hovercard-type=\"commit\" data-hovercard-url=\"https://github.com/postgres/postgres/commit/5bf748b86bc6786a3fc57fc7ce296c37da6564b0/hovercard\" href=\"https://github.com/postgres/postgres/commit/5bf748b86bc6786a3fc57fc7ce296c37da6564b0\"\u003e\u003ctt\u003e5bf748b\u003c/tt\u003e\u003c/a\u003e, which enhanced nbtree ScalarArrayOp\nexecution.\n\nAuthor: Peter Geoghegan \u0026lt;pg@bowt.ie\u0026gt;\nDiscussion: \u003ca href=\"https://postgr.es/m/CAH2-Wznv49bFsE2jkt4GuZ0tU2C91dEST=50egzjY2FeOcHL4Q@mail.gmail.com\" rel=\"nofollow\"\u003ehttps://postgr.es/m/CAH2-Wznv49bFsE2jkt4GuZ0tU2C91dEST=50egzjY2FeOcHL4Q@mail.gmail.com\u003c/a\u003e\nBackpatch: 17-, where commit \u003ca class=\"commit-link\" data-hovercard-type=\"commit\" data-hovercard-url=\"https://github.com/postgres/postgres/commit/5bf748b86bc6786a3fc57fc7ce296c37da6564b0/hovercard\" href=\"https://github.com/postgres/postgres/commit/5bf748b86bc6786a3fc57fc7ce296c37da6564b0\"\u003e\u003ctt\u003e5bf748b\u003c/tt\u003e\u003c/a\u003e first appears.","authors":[{"login":"petergeoghegan","displayName":"Peter Geoghegan","avatarUrl":"https://avatars.githubusercontent.com/u/779307?v=4","path":"/petergeoghegan","isGitHub":false}],"committerAttribution":false,"committer":{"login":"petergeoghegan","displayName":"Peter Geoghegan","avatarUrl":"https://avatars.githubusercontent.com/u/779307?v=4","path":"/petergeoghegan","isGitHub":false},"parents":["2d5fe514052ad82e46612e4c572f1c999be56a71"],"globalRelayId":"C_kwDOAA4m0toAKDc2M2Q2NWFlMjU0NTY5ZTBiZGJlMmNiYjI3YjE4NDExMjc2NWYyNGY","sha1":"2d5fe514052ad82e46612e4c572f1c999be56a71","sha2":"763d65ae254569e0bdbe2cbb27b184112765f24f"},"currentUser":null,"repo":{"id":927442,"defaultBranch":"master","name":"postgres","ownerLogin":"postgres","currentUserCanPush":false,"isFork":false,"isEmpty":false,"createdAt":"2010-09-21T11:35:45.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/177543?v=4","public":true,"private":false,"isOrgOwned":true},"diffEntryData":[{"diffLines":[{"stylingDirective":null,"type":"HUNK","blobLineNumber":1567,"text":"@@ -1568,6 +1568,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,","html":"@@ -1568,6 +1568,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,","displayNoNewLineWarning":false,"position":0,"left":1567,"right":1567},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1568,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":1,"left":1568,"right":1568},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1569,"text":" \tAssert(!P_IGNORE(opaque));","html":" \t\u003cspan class=pl-en\u003eAssert\u003c/span\u003e(!\u003cspan class=pl-en\u003eP_IGNORE\u003c/span\u003e(\u003cspan class=pl-s1\u003eopaque\u003c/span\u003e));","displayNoNewLineWarning":false,"position":2,"left":1569,"right":1569},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1570,"text":" \tAssert(BTScanPosIsPinned(so-\u003ecurrPos));","html":" \t\u003cspan class=pl-en\u003eAssert\u003c/span\u003e(\u003cspan class=pl-en\u003eBTScanPosIsPinned\u003c/span\u003e(\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003ecurrPos\u003c/span\u003e));","displayNoNewLineWarning":false,"position":3,"left":1570,"right":1570},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":1571,"text":"+\tAssert(!so-\u003eneedPrimScan);","html":"+\t\u003cspan class=pl-en\u003eAssert\u003c/span\u003e(!\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eneedPrimScan\u003c/span\u003e);","displayNoNewLineWarning":false,"position":4,"left":1570,"right":1571},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1572,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":5,"left":1571,"right":1572},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1573,"text":" \tif (scan-\u003eparallel_scan)","html":" \t\u003cspan class=pl-k\u003eif\u003c/span\u003e (\u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eparallel_scan\u003c/span\u003e)","displayNoNewLineWarning":false,"position":6,"left":1572,"right":1573},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1574,"text":" \t{","html":" \t{","displayNoNewLineWarning":false,"position":7,"left":1573,"right":1574},{"stylingDirective":null,"type":"HUNK","blobLineNumber":1594,"text":"@@ -1594,7 +1595,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,","html":"@@ -1594,7 +1595,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,","displayNoNewLineWarning":false,"position":8,"left":1593,"right":1594},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1595,"text":" \tmaxoff = PageGetMaxOffsetNumber(page);","html":" \t\u003cspan class=pl-s1\u003emaxoff\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-en\u003ePageGetMaxOffsetNumber\u003c/span\u003e(\u003cspan class=pl-s1\u003epage\u003c/span\u003e);","displayNoNewLineWarning":false,"position":9,"left":1594,"right":1595},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1596,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":10,"left":1595,"right":1596},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1597,"text":" \t/* initialize page-level state that we'll pass to _bt_checkkeys */","html":" \t\u003cspan class=pl-c\u003e/* initialize page-level state that we\u0026#39;ll pass to _bt_checkkeys */\u003c/span\u003e","displayNoNewLineWarning":false,"position":11,"left":1596,"right":1597},{"stylingDirective":null,"type":"DELETION","blobLineNumber":1597,"text":"-\tpstate.dir = dir;","html":"-\t\u003cspan class=pl-s1\u003epstate\u003c/span\u003e.\u003cspan class=pl-c1\u003edir\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":12,"left":1597,"right":1597},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1598,"text":" \tpstate.minoff = minoff;","html":" \t\u003cspan class=pl-s1\u003epstate\u003c/span\u003e.\u003cspan class=pl-c1\u003eminoff\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003eminoff\u003c/span\u003e;","displayNoNewLineWarning":false,"position":13,"left":1598,"right":1598},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1599,"text":" \tpstate.maxoff = maxoff;","html":" \t\u003cspan class=pl-s1\u003epstate\u003c/span\u003e.\u003cspan class=pl-c1\u003emaxoff\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003emaxoff\u003c/span\u003e;","displayNoNewLineWarning":false,"position":14,"left":1599,"right":1599},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1600,"text":" \tpstate.finaltup = NULL;","html":" \t\u003cspan class=pl-s1\u003epstate\u003c/span\u003e.\u003cspan class=pl-c1\u003efinaltup\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-c1\u003eNULL\u003c/span\u003e;","displayNoNewLineWarning":false,"position":15,"left":1600,"right":1600},{"stylingDirective":null,"type":"HUNK","blobLineNumber":2087,"text":"@@ -2088,7 +2088,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","html":"@@ -2088,7 +2088,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","displayNoNewLineWarning":false,"position":16,"left":2087,"right":2087},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2088,"text":" \t\t */","html":" \u003cspan class=pl-c\u003e\t\t */\u003c/span\u003e","displayNoNewLineWarning":false,"position":17,"left":2088,"right":2088},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2089,"text":" \t\tif (so-\u003eneedPrimScan)","html":" \t\t\u003cspan class=pl-k\u003eif\u003c/span\u003e (\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eneedPrimScan\u003c/span\u003e)","displayNoNewLineWarning":false,"position":18,"left":2089,"right":2089},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2090,"text":" \t\t{","html":" \t\t{","displayNoNewLineWarning":false,"position":19,"left":2090,"right":2090},{"stylingDirective":null,"type":"DELETION","blobLineNumber":2091,"text":"-\t\t\tif (ScanDirectionIsForward(dir))","html":"-\t\t\t\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003eScanDirectionIsForward\u003c/span\u003e(\u003cspan class=\"pl-s1\"\u003edir\u003c/span\u003e))","displayNoNewLineWarning":false,"position":20,"left":2091,"right":2090},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2091,"text":"+\t\t\tif (ScanDirectionIsForward(so-\u003ecurrPos.dir))","html":"+\t\t\t\u003cspan class=\"pl-k\"\u003eif\u003c/span\u003e (\u003cspan class=\"pl-en\"\u003eScanDirectionIsForward\u003c/span\u003e(\u003cspan class=\"pl-s1 x x-first\"\u003eso\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003ecurrPos\u003c/span\u003e\u003cspan class=\"x x-last\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003edir\u003c/span\u003e))","displayNoNewLineWarning":false,"position":21,"left":2091,"right":2091},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2092,"text":" \t\t\t\tso-\u003emarkPos.moreRight = true;","html":" \t\t\t\t\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003emarkPos\u003c/span\u003e.\u003cspan class=pl-c1\u003emoreRight\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e true;","displayNoNewLineWarning":false,"position":22,"left":2092,"right":2092},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2093,"text":" \t\t\telse","html":" \t\t\t\u003cspan class=pl-k\u003eelse\u003c/span\u003e","displayNoNewLineWarning":false,"position":23,"left":2093,"right":2093},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2094,"text":" \t\t\t\tso-\u003emarkPos.moreLeft = true;","html":" \t\t\t\t\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003emarkPos\u003c/span\u003e.\u003cspan class=pl-c1\u003emoreLeft\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e true;","displayNoNewLineWarning":false,"position":24,"left":2094,"right":2094},{"stylingDirective":null,"type":"HUNK","blobLineNumber":2108,"text":"@@ -2109,6 +2109,15 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","html":"@@ -2109,6 +2109,15 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","displayNoNewLineWarning":false,"position":25,"left":2108,"right":2108},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2109,"text":" \t\telse","html":" \t\t\u003cspan class=pl-k\u003eelse\u003c/span\u003e","displayNoNewLineWarning":false,"position":26,"left":2109,"right":2109},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2110,"text":" \t\t\tblkno = so-\u003ecurrPos.prevPage;","html":" \t\t\t\u003cspan class=pl-s1\u003eblkno\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003ecurrPos\u003c/span\u003e.\u003cspan class=pl-c1\u003eprevPage\u003c/span\u003e;","displayNoNewLineWarning":false,"position":27,"left":2110,"right":2110},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2111,"text":" \t\tlastcurrblkno = so-\u003ecurrPos.currPage;","html":" \t\t\u003cspan class=pl-s1\u003elastcurrblkno\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003ecurrPos\u003c/span\u003e.\u003cspan class=pl-c1\u003ecurrPage\u003c/span\u003e;","displayNoNewLineWarning":false,"position":28,"left":2111,"right":2111},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2112,"text":"+","html":"+","displayNoNewLineWarning":false,"position":29,"left":2111,"right":2112},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2113,"text":"+\t\t/*","html":"+\t\t\u003cspan class=pl-c\u003e/*\u003c/span\u003e","displayNoNewLineWarning":false,"position":30,"left":2111,"right":2113},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2114,"text":"+\t\t * Cancel primitive index scans that were scheduled when the call to","html":"+\u003cspan class=pl-c\u003e\t\t * Cancel primitive index scans that were scheduled when the call to\u003c/span\u003e","displayNoNewLineWarning":false,"position":31,"left":2111,"right":2114},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2115,"text":"+\t\t * _bt_readpage for currPos happened to use the opposite direction to","html":"+\u003cspan class=pl-c\u003e\t\t * _bt_readpage for currPos happened to use the opposite direction to\u003c/span\u003e","displayNoNewLineWarning":false,"position":32,"left":2111,"right":2115},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2116,"text":"+\t\t * the one that we're stepping in now. (It's okay to leave the scan's","html":"+\u003cspan class=pl-c\u003e\t\t * the one that we\u0026#39;re stepping in now. (It\u0026#39;s okay to leave the scan\u0026#39;s\u003c/span\u003e","displayNoNewLineWarning":false,"position":33,"left":2111,"right":2116},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2117,"text":"+\t\t * array keys as-is, since the next _bt_readpage will advance them.)","html":"+\u003cspan class=pl-c\u003e\t\t * array keys as-is, since the next _bt_readpage will advance them.)\u003c/span\u003e","displayNoNewLineWarning":false,"position":34,"left":2111,"right":2117},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2118,"text":"+\t\t */","html":"+\u003cspan class=pl-c\u003e\t\t */\u003c/span\u003e","displayNoNewLineWarning":false,"position":35,"left":2111,"right":2118},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2119,"text":"+\t\tif (so-\u003ecurrPos.dir != dir)","html":"+\t\t\u003cspan class=pl-k\u003eif\u003c/span\u003e (\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003ecurrPos\u003c/span\u003e.\u003cspan class=pl-c1\u003edir\u003c/span\u003e \u003cspan class=pl-c1\u003e!=\u003c/span\u003e \u003cspan class=pl-s1\u003edir\u003c/span\u003e)","displayNoNewLineWarning":false,"position":36,"left":2111,"right":2119},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2120,"text":"+\t\t\tso-\u003eneedPrimScan = false;","html":"+\t\t\t\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eneedPrimScan\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e false;","displayNoNewLineWarning":false,"position":37,"left":2111,"right":2120},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2121,"text":" \t}","html":" \t}","displayNoNewLineWarning":false,"position":38,"left":2112,"right":2121},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2122,"text":" \telse","html":" \t\u003cspan class=pl-k\u003eelse\u003c/span\u003e","displayNoNewLineWarning":false,"position":39,"left":2113,"right":2122},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2123,"text":" \t{","html":" \t{","displayNoNewLineWarning":false,"position":40,"left":2114,"right":2123},{"stylingDirective":null,"type":"HUNK","blobLineNumber":2126,"text":"@@ -2118,6 +2127,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","html":"@@ -2118,6 +2127,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)","displayNoNewLineWarning":false,"position":41,"left":2117,"right":2126},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2127,"text":" \t\t */","html":" \u003cspan class=pl-c\u003e\t\t */\u003c/span\u003e","displayNoNewLineWarning":false,"position":42,"left":2118,"right":2127},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2128,"text":" \t\tif (!_bt_parallel_seize(scan, \u0026blkno, \u0026lastcurrblkno, false))","html":" \t\t\u003cspan class=pl-k\u003eif\u003c/span\u003e (!\u003cspan class=pl-en\u003e_bt_parallel_seize\u003c/span\u003e(\u003cspan class=pl-s1\u003escan\u003c/span\u003e, \u003cspan class=pl-c1\u003e\u0026amp;\u003c/span\u003e\u003cspan class=pl-s1\u003eblkno\u003c/span\u003e, \u003cspan class=pl-c1\u003e\u0026amp;\u003c/span\u003e\u003cspan class=pl-s1\u003elastcurrblkno\u003c/span\u003e, false))","displayNoNewLineWarning":false,"position":43,"left":2119,"right":2128},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2129,"text":" \t\t\treturn false;","html":" \t\t\t\u003cspan class=pl-k\u003ereturn\u003c/span\u003e false;","displayNoNewLineWarning":false,"position":44,"left":2120,"right":2129},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2130,"text":"+","html":"+","displayNoNewLineWarning":false,"position":45,"left":2120,"right":2130},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2131,"text":"+\t\tAssert(!so-\u003eneedPrimScan);","html":"+\t\t\u003cspan class=pl-en\u003eAssert\u003c/span\u003e(!\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eneedPrimScan\u003c/span\u003e);","displayNoNewLineWarning":false,"position":46,"left":2120,"right":2131},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2132,"text":" \t}","html":" \t}","displayNoNewLineWarning":false,"position":47,"left":2121,"right":2132},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2133,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":48,"left":2122,"right":2133},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2134,"text":" \treturn _bt_readnextpage(scan, blkno, lastcurrblkno, dir);","html":" \t\u003cspan class=pl-k\u003ereturn\u003c/span\u003e \u003cspan class=pl-en\u003e_bt_readnextpage\u003c/span\u003e(\u003cspan class=pl-s1\u003escan\u003c/span\u003e, \u003cspan class=pl-s1\u003eblkno\u003c/span\u003e, \u003cspan class=pl-s1\u003elastcurrblkno\u003c/span\u003e, \u003cspan class=pl-s1\u003edir\u003c/span\u003e);","displayNoNewLineWarning":false,"position":49,"left":2123,"right":2134}],"diffNumber":0,"diffSize":"0 Bytes","isBinary":false,"isTooBig":false,"collapsed":false,"isSubmodule":false,"lineCount":2633,"linesChanged":15,"newTreeEntry":{"lineCount":2633,"path":"src/backend/access/nbtree/nbtsearch.c","mode":100644,"isGenerated":false},"oldTreeEntry":{"lineCount":0,"path":"src/backend/access/nbtree/nbtsearch.c","mode":100644},"linesAdded":13,"linesDeleted":2,"path":"src/backend/access/nbtree/nbtsearch.c","pathDigest":"ed9877644d30cdfa994c8310345e67300297730cc0d340364daea5744da431b1","status":"MODIFIED","truncatedReason":null,"oldOid":"2d5fe514052ad82e46612e4c572f1c999be56a71","newOid":"763d65ae254569e0bdbe2cbb27b184112765f24f","copilotChatReference":null,"deletedSha":"2d5fe514052ad82e46612e4c572f1c999be56a71","canToggleRichDiff":false,"defaultToRichDiff":false,"proseDifffHtml":null,"renderInfo":null,"dependencyDiffPath":null,"submodule":null},{"diffLines":[{"stylingDirective":null,"type":"HUNK","blobLineNumber":1799,"text":"@@ -1800,7 +1800,7 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,","html":"@@ -1800,7 +1800,7 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,","displayNoNewLineWarning":false,"position":0,"left":1799,"right":1799},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1800,"text":" {","html":" {","displayNoNewLineWarning":false,"position":1,"left":1800,"right":1800},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1801,"text":" \tBTScanOpaque so = (BTScanOpaque) scan-\u003eopaque;","html":" \t\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e (\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e) \u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eopaque\u003c/span\u003e;","displayNoNewLineWarning":false,"position":2,"left":1801,"right":1801},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1802,"text":" \tRelation\trel = scan-\u003eindexRelation;","html":" \t\u003cspan class=pl-smi\u003eRelation\u003c/span\u003e\t\u003cspan class=pl-s1\u003erel\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eindexRelation\u003c/span\u003e;","displayNoNewLineWarning":false,"position":3,"left":1802,"right":1802},{"stylingDirective":null,"type":"DELETION","blobLineNumber":1803,"text":"-\tScanDirection dir = pstate ? pstate-\u003edir : ForwardScanDirection;","html":"-\t\u003cspan class=\"pl-smi\"\u003eScanDirection\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edir\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1 x x-first\"\u003epstate\u003c/span\u003e\u003cspan class=\"x\"\u003e ? \u003c/span\u003e\u003cspan class=\"pl-s1 x\"\u003epstate\u003c/span\u003e\u003cspan class=\"pl-c1 x x-last\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003edir\u003c/span\u003e\u003cspan class=\"x x-first\"\u003e : \u003c/span\u003e\u003cspan class=\"pl-s1 x x-last\"\u003eForwardScanDirection\u003c/span\u003e;","displayNoNewLineWarning":false,"position":4,"left":1803,"right":1802},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":1803,"text":"+\tScanDirection dir = so-\u003ecurrPos.dir;","html":"+\t\u003cspan class=\"pl-smi\"\u003eScanDirection\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edir\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1 x x-first\"\u003eso\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003ecurrPos\u003c/span\u003e\u003cspan class=\"x x-last\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":5,"left":1803,"right":1803},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1804,"text":" \tint\t\t\tarrayidx = 0;","html":" \t\u003cspan class=pl-smi\u003eint\u003c/span\u003e\t\t\t\u003cspan class=pl-s1\u003earrayidx\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-c1\u003e0\u003c/span\u003e;","displayNoNewLineWarning":false,"position":6,"left":1804,"right":1804},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1805,"text":" \tbool\t\tbeyond_end_advance = false,","html":" \t\u003cspan class=pl-smi\u003ebool\u003c/span\u003e\t\t\u003cspan class=pl-s1\u003ebeyond_end_advance\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e false,","displayNoNewLineWarning":false,"position":7,"left":1805,"right":1805},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1806,"text":" \t\t\t\thas_required_opposite_direction_only = false,","html":" \t\t\t\t\u003cspan class=pl-s1\u003ehas_required_opposite_direction_only\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e false,","displayNoNewLineWarning":false,"position":8,"left":1806,"right":1806},{"stylingDirective":null,"type":"HUNK","blobLineNumber":2399,"text":"@@ -2400,8 +2400,10 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,","html":"@@ -2400,8 +2400,10 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,","displayNoNewLineWarning":false,"position":9,"left":2399,"right":2399},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2400,"text":" \t/*","html":" \t\u003cspan class=pl-c\u003e/*\u003c/span\u003e","displayNoNewLineWarning":false,"position":10,"left":2400,"right":2400},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2401,"text":" \t * End this primitive index scan, but schedule another.","html":" \u003cspan class=pl-c\u003e\t * End this primitive index scan, but schedule another.\u003c/span\u003e","displayNoNewLineWarning":false,"position":11,"left":2401,"right":2401},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2402,"text":" \t *","html":" \u003cspan class=pl-c\u003e\t *\u003c/span\u003e","displayNoNewLineWarning":false,"position":12,"left":2402,"right":2402},{"stylingDirective":null,"type":"DELETION","blobLineNumber":2403,"text":"-\t * Note: If the scan direction happens to change, this scheduled primitive","html":"-\u003cspan class=pl-c\u003e\t * Note: If the scan direction happens to change, this scheduled primitive\u003c/span\u003e","displayNoNewLineWarning":false,"position":13,"left":2403,"right":2402},{"stylingDirective":null,"type":"DELETION","blobLineNumber":2404,"text":"-\t * index scan won't go ahead after all.","html":"-\u003cspan class=pl-c\u003e\t * index scan won\u0026#39;t go ahead after all.\u003c/span\u003e","displayNoNewLineWarning":false,"position":14,"left":2404,"right":2402},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2403,"text":"+\t * Note: We make a soft assumption that the current scan direction will","html":"+\u003cspan class=pl-c\u003e\t * Note: We make a soft assumption that the current scan direction will\u003c/span\u003e","displayNoNewLineWarning":false,"position":15,"left":2404,"right":2403},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2404,"text":"+\t * also be used within _bt_next, when it is asked to step off this page.","html":"+\u003cspan class=pl-c\u003e\t * also be used within _bt_next, when it is asked to step off this page.\u003c/span\u003e","displayNoNewLineWarning":false,"position":16,"left":2404,"right":2404},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2405,"text":"+\t * It is up to _bt_next to cancel this scheduled primitive index scan","html":"+\u003cspan class=pl-c\u003e\t * It is up to _bt_next to cancel this scheduled primitive index scan\u003c/span\u003e","displayNoNewLineWarning":false,"position":17,"left":2404,"right":2405},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":2406,"text":"+\t * whenever it steps to a page in the direction opposite currPos.dir.","html":"+\u003cspan class=pl-c\u003e\t * whenever it steps to a page in the direction opposite currPos.dir.\u003c/span\u003e","displayNoNewLineWarning":false,"position":18,"left":2404,"right":2406},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2407,"text":" \t */","html":" \u003cspan class=pl-c\u003e\t */\u003c/span\u003e","displayNoNewLineWarning":false,"position":19,"left":2405,"right":2407},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2408,"text":" \tpstate-\u003econtinuescan = false;\t/* Tell _bt_readpage we're done... */","html":" \t\u003cspan class=pl-s1\u003epstate\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003econtinuescan\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e false;\t\u003cspan class=pl-c\u003e/* Tell _bt_readpage we\u0026#39;re done... */\u003c/span\u003e","displayNoNewLineWarning":false,"position":20,"left":2406,"right":2408},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":2409,"text":" \tso-\u003eneedPrimScan = true;\t/* ...but call _bt_first again */","html":" \t\u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eneedPrimScan\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e true;\t\u003cspan class=pl-c\u003e/* ...but call _bt_first again */\u003c/span\u003e","displayNoNewLineWarning":false,"position":21,"left":2407,"right":2409},{"stylingDirective":null,"type":"HUNK","blobLineNumber":3459,"text":"@@ -3458,7 +3460,7 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,","html":"@@ -3458,7 +3460,7 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,","displayNoNewLineWarning":false,"position":22,"left":3457,"right":3459},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3460,"text":" {","html":" {","displayNoNewLineWarning":false,"position":23,"left":3458,"right":3460},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3461,"text":" \tTupleDesc\ttupdesc = RelationGetDescr(scan-\u003eindexRelation);","html":" \t\u003cspan class=pl-smi\u003eTupleDesc\u003c/span\u003e\t\u003cspan class=pl-s1\u003etupdesc\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-en\u003eRelationGetDescr\u003c/span\u003e(\u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eindexRelation\u003c/span\u003e);","displayNoNewLineWarning":false,"position":24,"left":3459,"right":3461},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3462,"text":" \tBTScanOpaque so = (BTScanOpaque) scan-\u003eopaque;","html":" \t\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e (\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e) \u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eopaque\u003c/span\u003e;","displayNoNewLineWarning":false,"position":25,"left":3460,"right":3462},{"stylingDirective":null,"type":"DELETION","blobLineNumber":3461,"text":"-\tScanDirection dir = pstate-\u003edir;","html":"-\t\u003cspan class=\"pl-smi\"\u003eScanDirection\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edir\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1 x x-first\"\u003epstate\u003c/span\u003e\u003cspan class=\"pl-c1 x x-last\"\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":26,"left":3461,"right":3462},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":3463,"text":"+\tScanDirection dir = so-\u003ecurrPos.dir;","html":"+\t\u003cspan class=\"pl-smi\"\u003eScanDirection\u003c/span\u003e \u003cspan class=\"pl-s1\"\u003edir\u003c/span\u003e \u003cspan class=\"pl-c1\"\u003e=\u003c/span\u003e \u003cspan class=\"pl-s1 x x-first\"\u003eso\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003 8000 e-\u0026gt;\u003c/span\u003e\u003cspan class=\"pl-c1 x\"\u003ecurrPos\u003c/span\u003e\u003cspan class=\"x x-last\"\u003e.\u003c/span\u003e\u003cspan class=\"pl-c1\"\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":27,"left":3461,"right":3463},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3464,"text":" \tint\t\t\tikey = 0;","html":" \t\u003cspan class=pl-smi\u003eint\u003c/span\u003e\t\t\t\u003cspan class=pl-s1\u003eikey\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-c1\u003e0\u003c/span\u003e;","displayNoNewLineWarning":false,"position":28,"left":3462,"right":3464},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3465,"text":" \tbool\t\tres;","html":" \t\u003cspan class=pl-smi\u003ebool\u003c/span\u003e\t\t\u003cspan class=pl-s1\u003eres\u003c/span\u003e;","displayNoNewLineWarning":false,"position":29,"left":3463,"right":3465},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":3466,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":30,"left":3464,"right":3466},{"stylingDirective":null,"type":"HUNK","blobLineNumber":4063,"text":"@@ -4062,7 +4064,8 @@ static void","html":"@@ -4062,7 +4064,8 @@ static void","displayNoNewLineWarning":false,"position":31,"left":4061,"right":4063},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4064,"text":" _bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate,","html":" \u003cspan class=pl-en\u003e_bt_checkkeys_look_ahead\u003c/span\u003e(\u003cspan class=pl-smi\u003eIndexScanDesc\u003c/span\u003e \u003cspan class=pl-s1\u003escan\u003c/span\u003e, \u003cspan class=pl-smi\u003eBTReadPageState\u003c/span\u003e \u003cspan class=pl-c1\u003e*\u003c/span\u003e\u003cspan class=pl-s1\u003epstate\u003c/span\u003e,","displayNoNewLineWarning":false,"position":32,"left":4062,"right":4064},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4065,"text":" \t\t\t\t\t\t int tupnatts, TupleDesc tupdesc)","html":" \t\t\t\t\t\t \u003cspan class=pl-smi\u003eint\u003c/span\u003e \u003cspan class=pl-s1\u003etupnatts\u003c/span\u003e, \u003cspan class=pl-smi\u003eTupleDesc\u003c/span\u003e \u003cspan class=pl-s1\u003etupdesc\u003c/span\u003e)","displayNoNewLineWarning":false,"position":33,"left":4063,"right":4065},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4066,"text":" {","html":" {","displayNoNewLineWarning":false,"position":34,"left":4064,"right":4066},{"stylingDirective":null,"type":"DELETION","blobLineNumber":4065,"text":"-\tScanDirection dir = pstate-\u003edir;","html":"-\t\u003cspan class=pl-smi\u003eScanDirection\u003c/span\u003e \u003cspan class=pl-s1\u003edir\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003epstate\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":35,"left":4065,"right":4066},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":4067,"text":"+\tBTScanOpaque so = (BTScanOpaque) scan-\u003eopaque;","html":"+\t\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e (\u003cspan class=pl-smi\u003eBTScanOpaque\u003c/span\u003e) \u003cspan class=pl-s1\u003escan\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003eopaque\u003c/span\u003e;","displayNoNewLineWarning":false,"position":36,"left":4065,"right":4067},{"stylingDirective":null,"type":"ADDITION","blobLineNumber":4068,"text":"+\tScanDirection dir = so-\u003ecurrPos.dir;","html":"+\t\u003cspan class=pl-smi\u003eScanDirection\u003c/span\u003e \u003cspan class=pl-s1\u003edir\u003c/span\u003e \u003cspan class=pl-c1\u003e=\u003c/span\u003e \u003cspan class=pl-s1\u003eso\u003c/span\u003e\u003cspan class=pl-c1\u003e-\u0026gt;\u003c/span\u003e\u003cspan class=pl-c1\u003ecurrPos\u003c/span\u003e.\u003cspan class=pl-c1\u003edir\u003c/span\u003e;","displayNoNewLineWarning":false,"position":37,"left":4065,"right":4068},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4069,"text":" \tOffsetNumber aheadoffnum;","html":" \t\u003cspan class=pl-smi\u003eOffsetNumber\u003c/span\u003e \u003cspan class=pl-s1\u003eaheadoffnum\u003c/span\u003e;","displayNoNewLineWarning":false,"position":38,"left":4066,"right":4069},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4070,"text":" \tIndexTuple\tahead;","html":" \t\u003cspan class=pl-smi\u003eIndexTuple\u003c/span\u003e\t\u003cspan class=pl-s1\u003eahead\u003c/span\u003e;","displayNoNewLineWarning":false,"position":39,"left":4067,"right":4070},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":4071,"text":" ","html":"\u003cbr\u003e","displayNoNewLineWarning":false,"position":40,"left":4068,"right":4071}],"diffNumber":1,"diffSize":"0 Bytes","isBinary":false,"isTooBig":false,"collapsed":false,"isSubmodule":false,"lineCount":5171,"linesChanged":13,"newTreeEntry":{"lineCount":5171,"path":"src/backend/access/nbtree/nbtutils.c","mode":100644,"isGenerated":false},"oldTreeEntry":{"lineCount":0,"path":"src/backend/access/nbtree/nbtutils.c","mode":100644},"linesAdded":8,"linesDeleted":5,"path":"src/backend/access/nbtree/nbtutils.c","pathDigest":"ec99f9d40c4ae8c8d3df9539b022ab622368aa3b746de86aa21f12bed110bbe7","status":"MODIFIED","truncatedReason":null,"oldOid":"2d5fe514052ad82e46612e4c572f1c999be56a71","newOid":"763d65ae254569e0bdbe2cbb27b184112765f24f","copilotChatReference":null,"deletedSha":"2d5fe514052ad82e46612e4c572f1c999be56a71","canToggleRichDiff":false,"defaultToRichDiff":false,"proseDifffHtml":null,"renderInfo":null,"dependencyDiffPath":null,"submodule":null},{"diffLines":[{"stylingDirective":null,"type":"HUNK","blobLineNumber":1077,"text":"@@ -1078,7 +1078,6 @@ typedef BTScanOpaqueData *BTScanOpaque;","html":"@@ -1078,7 +1078,6 @@ typedef BTScanOpaqueData *BTScanOpaque;","displayNoNewLineWarning":false,"position":0,"left":1077,"right":1077},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1078,"text":" typedef struct BTReadPageState","html":" \u003cspan class=pl-k\u003etypedef\u003c/span\u003e \u003cspan class=pl-k\u003estruct\u003c/span\u003e \u003cspan class=pl-smi\u003eBTReadPageState\u003c/span\u003e","displayNoNewLineWarning":false,"position":1,"left":1078,"right":1078},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1079,"text":" {","html":" {","displayNoNewLineWarning":false,"position":2,"left":1079,"right":1079},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1080,"text":" \t/* Input parameters, set by _bt_readpage for _bt_checkkeys */","html":" \t\u003cspan class=pl-c\u003e/* Input parameters, set by _bt_readpage for _bt_checkkeys */\u003c/span\u003e","displayNoNewLineWarning":false,"position":3,"left":1080,"right":1080},{"stylingDirective":null,"type":"DELETION","blobLineNumber":1081,"text":"-\tScanDirection dir;\t\t\t/* current scan direction */","html":"-\t\u003cspan class=pl-smi\u003eScanDirection\u003c/span\u003e \u003cspan class=pl-c1\u003edir\u003c/span\u003e;\t\t\t\u003cspan class=pl-c\u003e/* current scan direction */\u003c/span\u003e","displayNoNewLineWarning":false,"position":4,"left":1081,"right":1080},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1081,"text":" \tOffsetNumber minoff;\t\t/* Lowest non-pivot tuple's offset */","html":" \t\u003cspan class=pl-smi\u003eOffsetNumber\u003c/span\u003e \u003cspan class=pl-c1\u003eminoff\u003c/span\u003e;\t\t\u003cspan class=pl-c\u003e/* Lowest non-pivot tuple\u0026#39;s offset */\u003c/span\u003e","displayNoNewLineWarning":false,"position":5,"left":1082,"right":1081},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1082,"text":" \tOffsetNumber maxoff;\t\t/* Highest non-pivot tuple's offset */","html":" \t\u003cspan class=pl-smi\u003eOffsetNumber\u003c/span\u003e \u003cspan class=pl-c1\u003emaxoff\u003c/span\u003e;\t\t\u003cspan class=pl-c\u003e/* Highest non-pivot tuple\u0026#39;s offset */\u003c/span\u003e","displayNoNewLineWarning":false,"position":6,"left":1083,"right":1082},{"stylingDirective":null,"type":"CONTEXT","blobLineNumber":1083,"text":" \tIndexTuple\tfinaltup;\t\t/* Needed by scans with array keys */","html":" \t\u003cspan class=pl-smi\u003eIndexTuple\u003c/span\u003e\t\u003cspan class=pl-c1\u003efinaltup\u003c/span\u003e;\t\t\u003cspan class=pl-c\u003e/* Needed by scans with array keys */\u003c/span\u003e","displayNoNewLineWarning":false,"position":7,"left":1084,"right":1083}],"diffNumber":2,"diffSize":"0 Bytes","isBinary":false,"isTooBig":false,"collapsed":false,"isSubmodule":false,"lineCount":1324,"linesChanged":1,"newTreeEntry":{"lineCount":1324,"path":"src/include/access/nbtree.h","mode":100644,"isGenerated":false},"oldTreeEntry":{"lineCount":0,"path":"src/include/access/nbtree.h","mode":100644},"linesAdded":0,"linesDeleted":1,"path":"src/include/access/nbtree.h","pathDigest":"ce7134b2dc88b8c56c804e33255f05d751e658d9be25fc7ef069b98b78e09ffe","status":"MODIFIED","truncatedReason":null,"oldOid":"2d5fe514052ad82e46612e4c572f1c999be56a71","newOid":"763d65ae254569e0bdbe2cbb27b184112765f24f","copilotChatReference":null,"deletedSha":"2d5fe514052ad82e46612e4c572f1c999be56a71","canToggleRichDiff":false,"defaultToRichDiff":false,"proseDifffHtml":null,"renderInfo":null,"dependencyDiffPath":null,"submodule":null}],"splitViewPreference":"unified","ignoreWhitespace":false,"repoOwnerGlobalRelayId":"MDEyOk9yZ2FuaXphdGlvbjE3NzU0Mw==","commentsPreference":"visible","diffLineSpacingPreference":"relaxed","useMonospaceFont":false,"pasteUrlLinkAsPlainText":false,"userNotices":[],"path":"/postgres/postgres/commit/763d65ae254569e0bdbe2cbb27b184112765f24f","fileTreeExpanded":true,"headerInfo":{"additions":21,"deletions":8,"filesChanged":3,"filesChangedString":"3"},"moreDiffsToLoad":false,"asyncDiffLoadInfo":{"startIndex":3,"truncated":false,"byteCount":3751,"lineShownCount":99},"commentInfo":{"canComment":false,"locked":false,"canLock":false,"repoArchived":false},"csrf_tokens":{"/users/diffview?diff=split":{"post":"WcHwBkJb0OHsrOZPgwb-Cfm7XS8yUvRc0Fw_X6l99yhYAO3VJd0qWmNwKNZaUzLSrRWFWVh9mJP_uwVTHJ3fZQ"},"/users/diffview?diff=unified":{"post":"l8W3Wh3_dvNdac3G7RUnvb1048RyFTRM4hSpo1umoTGWBKqJenmMSNK1A180QOtm6do7shg6WIPN85Ov7kaJfA"},"/notifications/thread":{"post":"v0wJK7mYilsaU_cQh0snzRRmaqcdfa-kIzvGL4mi7ZxlNODYAkbWxuiMDmDJfjsyF160bTSLYVJzUzfP1bTxbA"}}},"title":"Fix bug in nbtree array primitive scan scheduling. · postgres/postgres@763d65a","appPayload":{"helpUrl":"https://docs.github.com","findInDiffWorkerPath":"/assets-cdn/worker/find-in-diff-worker-2bfe39677d14.js","enabled_features":{"diff_ux_refresh_beta":false,"diff_inline_comments":true,"diff_ux_refresh_ssr_five":false,"diff_ux_refresh_ssr_ten":false,"react_diff_line_type_character_correction":true}}}

Commit 763d65a

Browse files
Fix bug in nbtree array primitive scan scheduling.
A bug in nbtree's handling of primitive index scan scheduling could lead to wrong answers when a scrollable cursor was used with an index scan that had a SAOP index qual. Wrong answers were only possible when the scan direction changed after a primitive scan was scheduled, but before _bt_next was asked to fetch the next tuple in line (i.e. for things to break, _bt_next had to be denied the opportunity to step off the page in the same direction as the one used when the primscan was scheduled). Furthermore, the issue only occurred when the page in question happened to be the first page to be visited by the entire top-level scan; the issue hinged upon the cursor backing up to the absolute beginning of the key space that it returns tuples from (fetching in the opposite scan direction across a "primitive scan boundary" always worked correctly). To fix, make _bt_next unset the "needs primitive index scan" flag when it detects that the current scan direction is not the one that was used by _bt_readpage back when the primitive scan in question was scheduled. This fixes the cases that are known to be faulty, and also seems like a good idea on general robustness grounds. Affected scrollable cursor cases now avoid a spurious primitive index scan when they fetch backwards to the absolute start of the key space to be visited by their cursor. Fetching backwards now only returns those tuples at the start of the scan, as expected. It'll also be okay to once again fetch forwards from the start at that point, since the scan will be left in a state that's exactly consistent with the state it was in before any tuples were ever fetched, as expected. Oversight in commit 5bf748b, which enhanced nbtree ScalarArrayOp execution. Author: Peter Geoghegan <pg@bowt.ie> Discussion: https://postgr.es/m/CAH2-Wznv49bFsE2jkt4GuZ0tU2C91dEST=50egzjY2FeOcHL4Q@mail.gmail.com Backpatch: 17-, where commit 5bf748b first appears.
1 parent 2d5fe51 commit 763d65a

File tree

3 files changed

+21
-8
lines changed

3 files changed

+21
-8
lines changed

src/backend/access/nbtree/nbtsearch.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1568,6 +1568,7 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
15681568

15691569
Assert(!P_IGNORE(opaque));
15701570
Assert(BTScanPosIsPinned(so->currPos));
1571+
Assert(!so->needPrimScan);
15711572

15721573
if (scan->parallel_scan)
15731574
{
@@ -1594,7 +1595,6 @@ _bt_readpage(IndexScanDesc scan, ScanDirection dir, OffsetNumber offnum,
15941595
maxoff = PageGetMaxOffsetNumber(page);
15951596

15961597
/* initialize page-level state that we'll pass to _bt_checkkeys */
1597-
pstate.dir = dir;
15981598
pstate.minoff = minoff;
15991599
pstate.maxoff = maxoff;
16001600
pstate.finaltup = NULL;
@@ -2088,7 +2088,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
20882088
*/
20892089
if (so->needPrimScan)
20902090
{
2091-
if (ScanDirectionIsForward(dir))
2091+
if (ScanDirectionIsForward(so->currPos.dir))
20922092
so->markPos.moreRight = true;
20932093
else
20942094
so->markPos.moreLeft = true;
@@ -2109,6 +2109,15 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
21092109
else
21102110
blkno = so->currPos.prevPage;
21112111
lastcurrblkno = so->currPos.currPage;
2112+
2113+
/*
2114+
* Cancel primitive index scans that were scheduled when the call to
2115+
* _bt_readpage for currPos happened to use the opposite direction to
2116+
* the one that we're stepping in now. (It's okay to leave the scan's
2117+
* array keys as-is, since the next _bt_readpage will advance them.)
2118+
*/
2119+
if (so->currPos.dir != dir)
2120+
so->needPrimScan = false;
21122121
}
21132122
else
21142123
{
@@ -2118,6 +2127,8 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
21182127
*/
21192128
if (!_bt_parallel_seize(scan, &blkno, &lastcurrblkno, false))
21202129
return false;
2130+
2131+
Assert(!so->needPrimScan);
21212132
}
21222133

21232134
return _bt_readnextpage(scan, blkno, lastcurrblkno, dir);

src/backend/access/nbtree/nbtutils.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,7 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
18001800
{
18011801
BTScanOpaque so = (BTScanOpaque) scan->opaque;
18021802
Relation rel = scan->indexRelation;
1803-
ScanDirection dir = pstate ? pstate->dir : ForwardScanDirection;
1803+
ScanDirection dir = so->currPos.dir;
18041804
int arrayidx = 0;
18051805
bool beyond_end_advance = false,
18061806
has_required_opposite_direction_only = false,
@@ -2400,8 +2400,10 @@ _bt_advance_array_keys(IndexScanDesc scan, BTReadPageState *pstate,
24002400
/*
24012401
* End this primitive index scan, but schedule another.
24022402
*
2403-
* Note: If the scan direction happens to change, this scheduled primitive
2404-
* index scan won't go ahead after all.
2403+
* Note: We make a soft assumption that the current scan direction will
2404+
* also be used within _bt_next, when it is asked to step off this page.
2405+
* It is up to _bt_next to cancel this scheduled primitive index scan
2406+
* whenever it steps to a page in the direction opposite currPos.dir.
24052407
*/
24062408
pstate->continuescan = false; /* Tell _bt_readpage we're done... */
24072409
so->needPrimScan = true; /* ...but call _bt_first again */
@@ -3458,7 +3460,7 @@ _bt_checkkeys(IndexScanDesc scan, BTReadPageState *pstate, bool arrayKeys,
34583460
{
34593461
TupleDesc tupdesc = RelationGetDescr(scan->indexRelation);
34603462
BTScanOpaque so = (BTScanOpaque) scan->opaque;
3461-
ScanDirection dir = pstate->dir;
3463+
ScanDirection dir = so->currPos.dir;
34623464
int ikey = 0;
34633465
bool res;
34643466

@@ -4062,7 +4064,8 @@ static void
40624064
_bt_checkkeys_look_ahead(IndexScanDesc scan, BTReadPageState *pstate,
40634065
int tupnatts, TupleDesc tupdesc)
40644066
{
4065-
ScanDirection dir = pstate->dir;
4067+
BTScanOpaque so = (BTScanOpaque) scan->opaque;
4068+
ScanDirection dir = so->currPos.dir;
40664069
OffsetNumber aheadoffnum;
40674070
IndexTuple ahead;
40684071

src/include/access/nbtree.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1078,7 +1078,6 @@ typedef BTScanOpaqueData *BTScanOpaque;
10781078
typedef struct BTReadPageState
10791079
{
10801080
/* Input parameters, set by _bt_readpage for _bt_checkkeys */
1081-
ScanDirection dir; /* current scan direction */
10821081
OffsetNumber minoff; /* Lowest non-pivot tuple's offset */
10831082
OffsetNumber maxoff; /* Highest non-pivot tuple's offset */
10841083
IndexTuple finaltup; /* Needed by scans with array keys */

0 commit comments

Comments
 (0)
0