Michael Richards wrote:
> 
>  I need a little help on the format of the postgres tables.
> 
>  I've got this wonderfully corrupted database where just about everything is
>  fubar. I've tried a number of things to get it back using postgres and
>  related tools with no success. It looks like most of the data is there, but
>  there may be a small amount of corruption that's causing all kinds of
>  problems.

Find attached a python script that I used to get deleted (actually all
;) 
records from a database table.

It was not corrupted, just a simple programming error in client software 
had deleted more than needed. 

Fortunately it was not vacuumed so the data itself (info for web-based
paper 
postcard sending system) was there 

It works as-is only for my table as the field extraction code is
hard-coded, but 
it should be quite easy to modify for your needs

It worked 1 year ago probably on 6.4.x . I hope that the structure had
not 
changed since.

sendcard.py is the actual script used, pgtabdump.py is a somewhat
cleaned-up version


---------------
Hannu
#!/usr/bin/python

import sys,os,struct,string

site_base = "/var/lib/pgsql/base"
db_name = "betest"
table_name = "test"

db_path = os.path.join(site_base,db_name)
table_path = os.path.join(db_path,table_name)

page_size = 8*1024

def strbits(s,len):
    bits = []
    while s:
        c = s[0]
        s = s[1:]
        b = struct.unpack('B',c)[0]
        for i in range(8):
            if b & (1<<i): bits.append(1)
            else: bits.append(0)
    return string.join(map(str,bits),'')[:len]


class table_page:
    "class to represent a database table page"
    def __init__(self,fd,page_nr):
        fd.seek(page_nr*page_size)
        self.rawdata = fd.read(page_size)
        self.lower,\
        self.upper,\
        self.special,\
        self.opaque = struct.unpack('HHHH',self.rawdata[:8])
        self.item_pointers=[]
        self.items=[]
        for i in range(8,self.lower,4):
            rawItemIdData = self.rawdata[i:i+4]
            ItemIdData_I32 = struct.unpack('L',rawItemIdData)[0]
            if not ItemIdData_I32: break
            lp_len = int(ItemIdData_I32 >> 17)
            lp_flags = int((ItemIdData_I32 >> 15) & 3)
            lp_off = int(ItemIdData_I32 & 0x7fff)

            self.item_pointers.append(hex(ItemIdData_I32),lp_off,lp_flags,lp_len)
            rawItemData = self.rawdata[lp_off:lp_off+lp_len]
            t_oid  = struct.unpack('L', rawItemData[ 0: 4])[0]
            t_001  = struct.unpack('L', rawItemData[ 4: 8])[0]
            t_002  = struct.unpack('L', rawItemData[ 8:12])[0]
            t_xmin = struct.unpack('L', rawItemData[12:16])[0]
            t_xmax = struct.unpack('L', rawItemData[16:20])[0]
            t_ctid = struct.unpack('LH', rawItemData[20:26])  
            t_fcnt = struct.unpack('H', rawItemData[26:28])[0]
            t_xxx  = struct.unpack('2B', rawItemData[28:30])  
            t_doff = struct.unpack('B', rawItemData[30:31])[0]
            t_mask = strbits(rawItemData[31:t_doff],t_fcnt)   
#            t_mask = rawItemData[31:t_doff]
            t_data = rawItemData[t_doff:]   
            
self.items.append(t_oid,t_001,t_002,t_xmin,t_xmax,t_ctid,t_fcnt,t_xxx,t_doff,t_mask,t_data)
    def __str__(self):
        strval = [str((self.lower, self.upper, self.special, self.opaque))]
        strval.append(string.join(map(str,self.item_pointers),'\n'))
        strval.append(string.join(map(repr,self.items),'\n'))
        return string.join(strval,'\n------------------\n')  


if __name__=="__main__":
    print '# dumping %s' % table_path
    fd = open(table_name)
    page = table_page(fd,0)
    print page
#!/usr/bin/python

import sys,os,struct,string

table_name = "sendcard"

page_size = 8*1024

def strbits(s,len):
    bits = []
    while s:
        c = s[0]
        s = s[1:]
        b = struct.unpack('B',c)[0]
        for i in range(8):
            if b & (1<<i): bits.append(1)
            else: bits.append(0)
    bits = string.join(map(str,bits[:len]), '')
    return bits

"""
rapos=> \d sendcard
Table    = sendcard
+----------------------------------+----------------------------------+-------+
|              Field               |              Type                | Length|
+----------------------------------+----------------------------------+-------+
| card_id                          | int4 default nextval ( 'card_id_ |     4 |
| card_name                        | text                             |   var |
| recipient_name                   | text                             |   var |
| recipient_street_name            | text                             |   var |
| recipient_house_nr               | text                             |   var |
| recipient_apartment_nr           | text                             |   var |
| recipient_city                   | text                             |   var |
| recipient_village                | text                             |   var |
| recipient_state                  | text                             |   var |
| recipient_zip_code               | text                             |   var |
| sender_name                      | text                             |   var |
| sender_email                     | text                             |   var |
| message                          | text                             |   var |
| bank_ref_id                      | text                             |   var |
| delivery_nr                      | text                             |   var |
| delivery_route                   | text                             |   var |
| sender_remote_addr               | text                             |   var |
| card_cost                        | float8                           |     8 |
| cookie_id                        | int4 default nextval ( 'cookie_i |     4 |
| is_payed                         | text                             |   var |
| printing_date                    | datetime                         |     8 |
| delivery_date                    | date                             |     4 |
| payment_date                     | date                             |     4 |
| entered_at                       | timestamp default now ( )        |     4 |
| send_bill_to                     | text                             |   var |
+----------------------------------+----------------------------------+-------+
"""
create_statement = """\
create table savecard( 
    u_oid                  int,
    u_xmin                 int,
    u_xmax                 int,
    card_id                int4,
    card_name              text,
    recipient_name         text,
    recipient_street_name  text,
    recipient_house_nr     text,
    recipient_apartment_nr text,
    recipient_city         text,
    recipient_village      text,
    recipient_state        text,
    recipient_zip_code     text,
    sender_name            text,
    sender_email           text,
    message                text,
    bank_ref_id            text,
    delivery_nr            text,
    delivery_route         text,
    sender_remote_addr     text 
);
copy savecard from stdin;
"""
   
def bin2text(buf,offset):
    offset = ((offset + 3)/4)*4
    len = int(struct.unpack('L',buf[offset:offset+4])[0])
    str = buf[offset+4:offset+len]
    newoff = offset+len
    return str,newoff  
class table_page:
    "class to represent a database table page"
    def __init__(self,fd,page_nr):
        fd.seek(page_nr*page_size)
        self.rawdata = fd.read(page_size)
        self.lower,\
        self.upper,\
        self.special,\
        self.opaque = struct.unpack('HHHH',self.rawdata[:8])
        self.item_pointers=[]
        self.items=[]
        for i in range(8,self.lower,4):
            rawItemIdData = self.rawdata[i:i+4]
            ItemIdData_I32 = struct.unpack('L',rawItemIdData)[0]
            if not ItemIdData_I32: break
            lp_len = int(ItemIdData_I32 >> 17)
            lp_flags = int((ItemIdData_I32 >> 15) & 3)
            lp_off = int(ItemIdData_I32 & 0x7fff)

            self.item_pointers.append(hex(ItemIdData_I32),lp_off,lp_flags,lp_len)
            rawItemData = self.rawdata[lp_off:lp_off+lp_len]
            t_oid  = struct.unpack('L', rawItemData[ 0: 4])[0]
            t_001  = struct.unpack('L', rawItemData[ 4: 8])[0]
            t_002  = struct.unpack('L', rawItemData[ 8:12])[0]
            t_xmin = struct.unpack('L', rawItemData[12:16])[0]
            t_xmax = struct.unpack('L', rawItemData[16:20])[0]
            t_ctid = struct.unpack('LH', rawItemData[20:26])  
            t_fcnt = struct.unpack('H', rawItemData[26:28])[0]
            t_xxx  = struct.unpack('2B', rawItemData[28:30])  
            t_doff = struct.unpack('B', rawItemData[30:31])[0]
            t_mask = strbits(rawItemData[31:t_doff],t_fcnt)   
            t_data = rawItemData[t_doff:]
            id = int(struct.unpack('L',t_data[:4])[0])
            values = [int(t_oid),int(t_xmin),int(t_xmax),id]
            texts = []
            offset = 4
            for c in t_mask[1:17]:
                if not int(c):
                    values.append('')
                    continue
                text,offset = bin2text(t_data,offset)
                values.append(repr(text))
            values=values+texts
            self.items.append(values)
#            
self.items.append(t_oid,t_001,t_002,t_xmin,t_xmax,t_ctid,t_fcnt,t_xxx,t_doff,t_mask,t_data)
    def __str__(self):
#        strval = [str((self.lower, self.upper, self.special, self.opaque))]
#        strval.append(string.join(map(str,self.item_pointers),'\n'))
#        strval.append(string.join(map(repr,self.items),'\n'))
#        return string.join(strval,'\n------------------\n')  
        rows = []
        for record in self.items:
            rows.append(string.join(map(str,record),'\t'))
        return string.join(rows,'\n')

if __name__=="__main__":
#    print '# dumping %s' % table_name
    print create_statement
    fd = open(table_name) 
    page_nr = 0
    while 1:   
        try:   
            page = table_page(fd,page_nr)
            print page
        except:
            break
        page_nr = page_nr + 1
    print '\\.\n'

Reply via email to