FWIW, Bertrand blogged an even faster way to do this about a month ago - using 
pageinspect and processing blocks instead of rows

https://bdrouvot.wordpress.com/2020/01/18/retrieve-postgresql-variable-length-storage-information-thanks-to-pageinspect/

-J

Sent from my TI-83

> On Feb 17, 2020, at 03:32, Nick Renders <postg...@arcict.com> wrote:
> 
> The problem is that I don't know which column is corrupt. But I found a 
> solution: by simply copying the record into another variable, the values are 
> parsed and the TOAST errors are thrown.
> 
> In case anyone's interested, here's my code, based on an example from 
> http://www.databasesoup.com/2013/10/de-corrupting-toast-tables.html
> 
> 
> DO $f$
> DECLARE
>    rContent1 record;
>    rContent2 record;
>    iCounter integer DEFAULT 1;
>    iValue integer;
>    pTableName varchar := 'f_gsxws_transaction';
>    pFieldName varchar := 'gwta_number';
> BEGIN
>    FOR iValue IN EXECUTE 'SELECT ' || pFieldName || ' FROM ' || 
> pTableName::regclass || ' ORDER BY ' || pFieldName LOOP
>        BEGIN
>            EXECUTE 'SELECT * FROM ' || pTableName::regclass || ' WHERE ' || 
> pFieldName || ' = $1'
>                INTO rContent1
>                USING iValue;
>            rContent2 := rContent1;
>        EXCEPTION WHEN OTHERS THEN
>            RAISE NOTICE 'data for %.% % is corrupt', pTableName, pFieldName, 
> iValue;
>        END;
>        IF iCounter % 100000 = 0 THEN
>            RAISE NOTICE '% % records checked', iCounter, pTableName;
>        END IF;
>        iCounter := iCounter+1;
>    END LOOP;
> END;
> $f$;
> 
> 
> Cheers,
> 
> Nick
> 
> 
>> On 14 Feb 2020, at 16:14, Tom Lane wrote:
>> 
>> "Nick Renders" <postg...@arcict.com> writes:
>>> I thought I would write a little PL script that would loop through all
>>> the data and report any inconsistencies. However, I can't get it to work
>>> properly.
>>> ...
>>> 1) The function has no problem executing the SELECT statement. It is
>>> only when "rcontents" is returned, that the function fails. This is a
>>> problem, because the ultimate goal is to loop through all records and
>>> only return/alert something in case of an error.
>>> 2) The function never enters the EXCEPTION clause. Instead, when it hits
>>> the RETURN command, it breaks and shows the same message as in pgAdmin:
>>> missing chunk number 0 for toast value 8289525 in pg_toast_5572299.
>> 
>> I think what's happening there is that the function doesn't try to
>> dereference the value's TOAST pointer during SELECT INTO.  It just stores
>> that pointer into a variable, and only sometime later when the actual
>> content of the value is demanded, do you see the error raised.
>> 
>> The solution to that is to do something that uses the contents of the
>> busted column right away while still inside the EXCEPTION block, perhaps
>> along the lines of "select md5(mycolumn) into local_variable from..."
>> 
>> A close reading of
>> 
>> https://www.postgresql.org/docs/current/storage-toast.html
>> 
>> would probably help you understand what's happening here.
>> 
>>            regards, tom lane
> 
> 

Reply via email to