|
21 | 21 | #include "access/table.h"
|
22 | 22 | #include "access/valid.h"
|
23 | 23 | #include "access/xact.h"
|
| 24 | +#include "catalog/catalog.h" |
24 | 25 | #include "catalog/pg_collation.h"
|
25 | 26 | #include "catalog/pg_operator.h"
|
26 | 27 | #include "catalog/pg_type.h"
|
@@ -1843,6 +1844,23 @@ ReleaseCatCacheList(CatCList *list)
|
1843 | 1844 | }
|
1844 | 1845 |
|
1845 | 1846 |
|
| 1847 | +/* |
| 1848 | + * equalTuple |
| 1849 | + * Are these tuples memcmp()-equal? |
| 1850 | + */ |
| 1851 | +static bool |
| 1852 | +equalTuple(HeapTuple a, HeapTuple b) |
| 1853 | +{ |
| 1854 | + uint32 alen; |
| 1855 | + uint32 blen; |
| 1856 | + |
| 1857 | + alen = a->t_len; |
| 1858 | + blen = b->t_len; |
| 1859 | + return (alen == blen && |
| 1860 | + memcmp((char *) a->t_data, |
| 1861 | + (char *) b->t_data, blen) == 0); |
| 1862 | +} |
| 1863 | + |
1846 | 1864 | /*
|
1847 | 1865 | * CatalogCacheCreateEntry
|
1848 | 1866 | * Create a new CatCTup entry, copying the given HeapTuple and other
|
@@ -1893,14 +1911,34 @@ CatalogCacheCreateEntry(CatCache *cache, HeapTuple ntp, SysScanDesc scandesc,
|
1893 | 1911 | */
|
1894 | 1912 | if (HeapTupleHasExternal(ntp))
|
1895 | 1913 | {
|
| 1914 | + bool need_cmp = IsInplaceUpdateOid(cache->cc_reloid); |
| 1915 | + HeapTuple before = NULL; |
| 1916 | + bool matches = true; |
| 1917 | + |
| 1918 | + if (need_cmp) |
| 1919 | + before = heap_copytuple(ntp); |
1896 | 1920 | dtp = toast_flatten_tuple(ntp, cache->cc_tupdesc);
|
1897 | 1921 |
|
1898 | 1922 | /*
|
1899 | 1923 | * The tuple could become stale while we are doing toast table
|
1900 |
| - * access (since AcceptInvalidationMessages can run then), so we |
1901 |
| - * must recheck its visibility afterwards. |
| 1924 | + * access (since AcceptInvalidationMessages can run then). |
| 1925 | + * equalTuple() detects staleness from inplace updates, while |
| 1926 | + * systable_recheck_tuple() detects staleness from normal updates. |
| 1927 | + * |
| 1928 | + * While this equalTuple() follows the usual rule of reading with |
| 1929 | + * a pin and no buffer lock, it warrants suspicion since an |
| 1930 | + * inplace update could appear at any moment. It's safe because |
| 1931 | + * the inplace update sends an invalidation that can't reorder |
| 1932 | + * before the inplace heap change. If the heap change reaches |
| 1933 | + * this process just after equalTuple() looks, we've not missed |
| 1934 | + * its inval. |
1902 | 1935 | */
|
1903 |
| - if (!systable_recheck_tuple(scandesc, ntp)) |
| 1936 | + if (need_cmp) |
| 1937 | + { |
| 1938 | + matches = equalTuple(before, ntp); |
| 1939 | + heap_freetuple(before); |
| 1940 | + } |
| 1941 | + if (!matches || !systable_recheck_tuple(scandesc, ntp)) |
1904 | 1942 | {
|
1905 | 1943 | heap_freetuple(dtp);
|
1906 | 1944 | return NULL;
|
|
0 commit comments