开发者

How to download Postgres bytea column as file

开发者 https://www.devze.com 2023-03-21 04:21 出处:网络
Currently, i have a number of files stored in postgres 8.4 as bytea. The file types are开发者_开发知识库 .doc, .odt, .pdf, .txt and etc.

Currently, i have a number of files stored in postgres 8.4 as bytea. The file types are开发者_开发知识库 .doc, .odt, .pdf, .txt and etc.

May i know how to download all the file stored in Postgres because i need to to do a backup. I need them in their original file type instead of bytea format.

Thanks!


One simple option is to use COPY command with encode to hex format and then apply xxd shell command (with -p continuous hexdump style switch). For example let's say I have jpg image in bytea column in samples table:

\copy (SELECT encode(file, 'hex') FROM samples LIMIT 1) TO
    '/home/grzegorz/Desktop/image.hex'

$ xxd -p -r image.hex > image.jpg

As I checked it works in practice.


Try this:

 COPY (SELECT yourbyteacolumn FROM yourtable WHERE <add your clauses here> ...) TO 'youroutputfile' (FORMAT binary)


Here's the simplest thing I could come up with:

psql -qAt "select encode(file,'base64') from files limit 1" | base64 -d

The -qAt is important as it strips off any formatting of the output. These options are available inside the psql shell, too.


base64

psql -Aqt -c "SELECT encode(content, 'base64') FROM ..." | base64 -d > file

xxd

psql -Aqt -c "SELECT encode(content, 'hex') FROM ..." | xxd -p -r > file


If you have a lot of data to download then you can get the lines first and then iterate through each one writing the bytea field to file.

$resource = pg_connect('host=localhost port=5432 dbname=website user=super password=************');

// grab all the user IDs
$userResponse = pg_query('select distinct(r.id) from resource r
                        join connection c on r.id = c.resource_id_from
                        join resource rfile on c.resource_id_to = rfile.id and         rfile.resource_type_id = 10
                        join file f on rfile.id = f.resource_id
                        join file_type ft on f.file_type_id = ft.id
                        where r.resource_type_id = 38');

// need to work through one by one to handle data
while($user = pg_fetch_array($userResponse)){
    $user_id = $user['id'];
    $query = 'select r.id, f.data, rfile.resource_type_id, ft.extension from resource r
                        join connection c on r.id = c.resource_id_from
                        join resource rfile on c.resource_id_to = rfile.id and rfile.resource_type_id = 10
                        join file f on rfile.id = f.resource_id
                        join file_type ft on f.file_type_id = ft.id
                        where r.resource_type_id = 38 and r.id = ' . $user_id;

    $fileResponse = pg_query($query);
    $fileData = pg_fetch_array($fileResponse);
    $data = pg_unescape_bytea($fileData['data']);
    $extension = $fileData['extension'];
    $fileId = $fileData['id'];
    $filename = $fileId . '.' . $extension;
    $fileHandle = fopen($filename, 'w');
    fwrite($fileHandle, $data);
    fclose($fileHandle);
}


DO $$ 
DECLARE   
   l_lob_id OID;
   r record; BEGIN

  for r in
    select data, filename from bytea_table

   LOOP
    l_lob_id:=lo_from_bytea(0,r.data);
    PERFORM lo_export(l_lob_id,'/home/...'||r.filename);
    PERFORM lo_unlink(l_lob_id);   
    END LOOP;

END; $$


Best I'm aware, bytea to file needs to be done at the app level.

(9.1 might change this with the filesystem data wrapper contrib. There's also a lo_export function, but it is not applicable here.)


If you want to do this from a local windows, and not from the server, you will have to run every statement individually, and have PGAdmin and certutil:

  1. Have PGAdmin installed.

  2. Open cmd from the runtime folder or cd "C:\Program Files\pgAdmin 4\v6\runtime"

  3. Run in PGAdmin query to get every statement that you will have to paste in cmd:

    SELECT 'set PGPASSWORD={PASSWORD} && psql -h {host} -U {user} -d {db name} -Aqt -c "SELECT encode({bytea_column}, ''base64'') FROM {table} WHERE id='||id||'" > %a% && CERTUTIL -decode %a% "C:\temp{name_of_the_folder}\FileName - '||{file_name}||' ('||TO_CHAR(current_timestamp(),'DD.MM.YYYY,HH24 MI SS')||').'||{file_extension}||'"' FROM table WHERE ....;

Replace {...}

It will generate something like:

set PGPASSWORD=123  psql -h 192.1.1.1 -U postgres -d my_test_db -Aqt -c "SELECT encode(file_bytea, 'base64') FROM test_table_bytea WHERE id=33" > %a% && CERTUTIL -decode %a% "C:\temp\DB_FILE\FileName - test1 - (06.04.2022,15 42 26).docx"
set PGPASSWORD=123  psql -h 192.1.1.1 -U postgres -d my_test_db -Aqt -c "SELECT encode(file_bytea, 'base64') FROM test_table_bytea WHERE id=44" > %a% && CERTUTIL -decode %a% "C:\temp\DB_FILE\FileName - test2 - (06.04.2022,15 42 26).pdf"
  1. Copy paste all the generated statements in CMD. The files will be saved to your local machine.
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号