Hi,
I have written my own 'large object'-like feature using the following table:
----
CREATE TABLE blob
(
id bigint NOT NULL,
pageno integer NOT NULL,
data bytea,
CONSTRAINT blob_pkey PRIMARY KEY (id, pageno)
)
WITHOUT OIDS;
ALTER TABLE blob ALTER COLUMN data SET STORAGE EXTERNAL;
CREATE SEQUENCE seq_key_blob;
----
One blob consist of many rows, each containing one 'page'. I insert pages with
PQexecPrepared with the format set to binary. This works quite well for the
following setups:
client -> server
-----------------
linux -> linux
linux -> windows
windows -> windows
but pretty bad (meaning about 10 times slower) for this setup
windows -> linux
The used postgresql versions are 8.1.5 for both operating system. A (sort of)
minimal code sample exposing this problem may be found appended to this e-mail.
Any ideas?
Thanks,
Axel
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef WIN32
#include <io.h>
#include <winsock2.h>
#else
#include <unistd.h>
#endif
#include "libpq-fe.h"
#include "libpq/libpq-fs.h"
#define BUFSIZE (1024*64)
static void exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
#define CHECK_PG_NO_RES(...) \
do{ \
PGresult* res = __VA_ARGS__; \
if( !res || (PQresultStatus(res) != PGRES_TUPLES_OK \
&& PQresultStatus(res) != PGRES_COMMAND_OK) ) \
{ \
printf("%s failed: %s", #__VA_ARGS__, PQerrorMessage(conn)); \
exit_nicely( conn ); \
} \
PQclear( res ); \
} while(0)
#define CHECK_PGRES(...) \
do { \
res = __VA_ARGS__; \
if( !res || (PQresultStatus(res) != PGRES_TUPLES_OK \
&& PQresultStatus(res) != PGRES_COMMAND_OK) ) \
{ \
printf("%s failed: %s", #__VA_ARGS__, PQerrorMessage(conn)); \
exit_nicely( conn ); \
} \
} while(0)
/*
* upload 10 MB dummy data, return blob-id
*/
static int upload(PGconn *conn)
{
char buf[BUFSIZE];
int id;
int id_n; // network byteorder of id
int pageno;
int pageno_n;
int N = 10*1024*1024/BUFSIZE;
const char* values[] = { (const char*)&id_n, (const char*)&pageno_n, buf };
const int formats[] = {1, 1, 1};
const int lengths[] = {sizeof(int), sizeof(int), BUFSIZE};
/*
* get (free) blob id
*/
PGresult* res;
CHECK_PGRES( PQexec( conn, "select nextval('seq_key_blob')" ) );
id = atoi( PQgetvalue(res, 0, 0) );
PQclear( res );
id_n = htonl(id);
/*
* prepare insert statement
*/
CHECK_PG_NO_RES( PQprepare( conn, "", "insert into blob (id, pageno, data) "
"values ($1::int4, $2::int4, $3::bytea);",
0, 0 ) );
printf("inserting %d pages (each %d kB): ", N, BUFSIZE/1024);
/*
* upload pages
*/
for( pageno = 0; pageno < N; ++pageno )
{
pageno_n = htonl(pageno);
CHECK_PG_NO_RES(
PQexecPrepared( conn, "", 3, values, lengths, formats, 1 ) );
printf(".");
fflush(stdout);
}
printf("\n");
return id;
}
/*
* download blob with given id
*/
static void download(PGconn *conn, int id)
{
char buf[BUFSIZE];
int id_n = htonl(id); // network byteorder of id
int pageno;
int pageno_n;
const char* values[] = { (const char*)&id_n, (const char*)&pageno_n };
const int lengths[] = {sizeof(int), sizeof(int)};
const int formats[] = {1, 1};
/*
* determine size of blob
*/
PGresult* res;
CHECK_PGRES( PQexecParams( conn, "select count(id) from blob where id = $1::int4;",
1, 0 /*type*/, values, lengths, formats, 0 ) );
int pages = atoi( PQgetvalue(res, 0, 0) );
PQclear( res );
printf("selecting %d pages (each %d kB): ", pages, BUFSIZE/1024);
/*
* prepare select statement
*/
CHECK_PG_NO_RES( PQprepare( conn, "", "select data from blob "
"where id = $1::int4 and pageno = $2::int4;",
0, 0 ) );
/*
* download pages
*/
for( pageno = 0; pageno < pages; ++pageno )
{
pageno_n = htonl(pageno);
CHECK_PGRES(
PQexecPrepared( conn, "", 2, values, lengths, formats, 1 ) );
/*
* we are not interested in the actual data in this demo
* n = PQgetlength( res, 0, 0 );
* v = PQgetvalue(res, 0, 0);
*/
PQclear( res );
printf(".");
fflush(stdout);
}
printf("\n");
return;
}
int main(int argc, char **argv)
{
int id;
PGconn *conn;
PGresult *res;
if (argc < 5)
{
fprintf(stderr, "Usage: %s host database user password\n", argv[0]);
exit(1);
}
/*
* set up the connection
*/
conn = PQsetdbLogin(argv[1], "5432", NULL, NULL, argv[2], argv[3], argv[4]);
/* check to see that the backend connection was successfully made */
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "Connection to database failed: %s",
PQerrorMessage(conn));
exit_nicely(conn);
}
id = upload( conn );
download( conn, id );
PQfinish(conn);
return 0;
}
---------------------------(end of broadcast)---------------------------
TIP 1: if posting/reading through Usenet, please send an appropriate
subscribe-nomail command to [EMAIL PROTECTED] so that your
message can get through to the mailing list cleanly