mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-17 21:10:06 +02:00
58cd8dca3d
libpq's error messages for connection failures pretty well stand on their own, especially since commits 52a10224e/27a48e5a1. Prefixing them with 'could not connect to database "foo"' or the like is just redundant, and perhaps even misleading if the specific database name isn't relevant to the failure. (When it is, we trust that the backend's error message will include the DB name.) Indeed, psql hasn't used any such prefix in a long time. So, make all our other programs and documentation examples agree with psql's practice. Discussion: https://postgr.es/m/1094524.1611266589@sss.pgh.pa.us
302 lines
6.4 KiB
C
302 lines
6.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* testlo64.c
|
|
* test using large objects with libpq using 64-bit APIs
|
|
*
|
|
* Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/test/examples/testlo64.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
|
|
#include "libpq-fe.h"
|
|
#include "libpq/libpq-fs.h"
|
|
|
|
#define BUFSIZE 1024
|
|
|
|
/*
|
|
* importFile -
|
|
* import file "in_filename" into database as large object "lobjOid"
|
|
*
|
|
*/
|
|
static Oid
|
|
importFile(PGconn *conn, char *filename)
|
|
{
|
|
Oid lobjId;
|
|
int lobj_fd;
|
|
char buf[BUFSIZE];
|
|
int nbytes,
|
|
tmp;
|
|
int fd;
|
|
|
|
/*
|
|
* open the file to be read in
|
|
*/
|
|
fd = open(filename, O_RDONLY, 0666);
|
|
if (fd < 0)
|
|
{ /* error */
|
|
fprintf(stderr, "cannot open unix file\"%s\"\n", filename);
|
|
}
|
|
|
|
/*
|
|
* create the large object
|
|
*/
|
|
lobjId = lo_creat(conn, INV_READ | INV_WRITE);
|
|
if (lobjId == 0)
|
|
fprintf(stderr, "cannot create large object");
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
|
|
|
|
/*
|
|
* read in from the Unix file and write to the inversion file
|
|
*/
|
|
while ((nbytes = read(fd, buf, BUFSIZE)) > 0)
|
|
{
|
|
tmp = lo_write(conn, lobj_fd, buf, nbytes);
|
|
if (tmp < nbytes)
|
|
fprintf(stderr, "error while reading \"%s\"", filename);
|
|
}
|
|
|
|
close(fd);
|
|
lo_close(conn, lobj_fd);
|
|
|
|
return lobjId;
|
|
}
|
|
|
|
static void
|
|
pickout(PGconn *conn, Oid lobjId, pg_int64 start, int len)
|
|
{
|
|
int lobj_fd;
|
|
char *buf;
|
|
int nbytes;
|
|
int nread;
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_READ);
|
|
if (lobj_fd < 0)
|
|
fprintf(stderr, "cannot open large object %u", lobjId);
|
|
|
|
if (lo_lseek64(conn, lobj_fd, start, SEEK_SET) < 0)
|
|
fprintf(stderr, "error in lo_lseek64: %s", PQerrorMessage(conn));
|
|
|
|
if (lo_tell64(conn, lobj_fd) != start)
|
|
fprintf(stderr, "error in lo_tell64: %s", PQerrorMessage(conn));
|
|
|
|
buf = malloc(len + 1);
|
|
|
|
nread = 0;
|
|
while (len - nread > 0)
|
|
{
|
|
nbytes = lo_read(conn, lobj_fd, buf, len - nread);
|
|
buf[nbytes] = '\0';
|
|
fprintf(stderr, ">>> %s", buf);
|
|
nread += nbytes;
|
|
if (nbytes <= 0)
|
|
break; /* no more data? */
|
|
}
|
|
free(buf);
|
|
fprintf(stderr, "\n");
|
|
lo_close(conn, lobj_fd);
|
|
}
|
|
|
|
static void
|
|
overwrite(PGconn *conn, Oid lobjId, pg_int64 start, int len)
|
|
{
|
|
int lobj_fd;
|
|
char *buf;
|
|
int nbytes;
|
|
int nwritten;
|
|
int i;
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_WRITE);
|
|
if (lobj_fd < 0)
|
|
fprintf(stderr, "cannot open large object %u", lobjId);
|
|
|
|
if (lo_lseek64(conn, lobj_fd, start, SEEK_SET) < 0)
|
|
fprintf(stderr, "error in lo_lseek64: %s", PQerrorMessage(conn));
|
|
|
|
buf = malloc(len + 1);
|
|
|
|
for (i = 0; i < len; i++)
|
|
buf[i] = 'X';
|
|
buf[i] = '\0';
|
|
|
|
nwritten = 0;
|
|
while (len - nwritten > 0)
|
|
{
|
|
nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten);
|
|
nwritten += nbytes;
|
|
if (nbytes <= 0)
|
|
{
|
|
fprintf(stderr, "\nWRITE FAILED!\n");
|
|
break;
|
|
}
|
|
}
|
|
free(buf);
|
|
fprintf(stderr, "\n");
|
|
lo_close(conn, lobj_fd);
|
|
}
|
|
|
|
static void
|
|
my_truncate(PGconn *conn, Oid lobjId, pg_int64 len)
|
|
{
|
|
int lobj_fd;
|
|
|
|
lobj_fd = lo_open(conn, lobjId, INV_READ | INV_WRITE);
|
|
if (lobj_fd < 0)
|
|
fprintf(stderr, "cannot open large object %u", lobjId);
|
|
|
|
if (lo_truncate64(conn, lobj_fd, len) < 0)
|
|
fprintf(stderr, "error in lo_truncate64: %s", PQerrorMessage(conn));
|
|
|
|
lo_close(conn, lobj_fd);
|
|
}
|
|
|
|
|
|
/*
|
|
* exportFile -
|
|
* export large object "lobjOid" to file "out_filename"
|
|
*
|
|
*/
|
|
static void
|
|
exportFile(PGconn *conn, Oid lobjId, char *filename)
|
|
{
|
|
int lobj_fd;
|
|
char buf[BUFSIZE];
|
|
int nbytes,
|
|
tmp;
|
|
int fd;
|
|
|
|
/*
|
|
* open the large object
|
|
*/
|
|
lobj_fd = lo_open(conn, lobjId, INV_READ);
|
|
if (lobj_fd < 0)
|
|
fprintf(stderr, "cannot open large object %u", lobjId);
|
|
|
|
/*
|
|
* open the file to be written to
|
|
*/
|
|
fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
|
|
if (fd < 0)
|
|
{ /* error */
|
|
fprintf(stderr, "cannot open unix file\"%s\"",
|
|
filename);
|
|
}
|
|
|
|
/*
|
|
* read in from the inversion file and write to the Unix file
|
|
*/
|
|
while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0)
|
|
{
|
|
tmp = write(fd, buf, nbytes);
|
|
if (tmp < nbytes)
|
|
{
|
|
fprintf(stderr, "error while writing \"%s\"",
|
|
filename);
|
|
}
|
|
}
|
|
|
|
lo_close(conn, lobj_fd);
|
|
close(fd);
|
|
}
|
|
|
|
static void
|
|
exit_nicely(PGconn *conn)
|
|
{
|
|
PQfinish(conn);
|
|
exit(1);
|
|
}
|
|
|
|
int
|
|
main(int argc, char **argv)
|
|
{
|
|
char *in_filename,
|
|
*out_filename,
|
|
*out_filename2;
|
|
char *database;
|
|
Oid lobjOid;
|
|
PGconn *conn;
|
|
PGresult *res;
|
|
|
|
if (argc != 5)
|
|
{
|
|
fprintf(stderr, "Usage: %s database_name in_filename out_filename out_filename2\n",
|
|
argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
database = argv[1];
|
|
in_filename = argv[2];
|
|
out_filename = argv[3];
|
|
out_filename2 = argv[4];
|
|
|
|
/*
|
|
* set up the connection
|
|
*/
|
|
conn = PQsetdb(NULL, NULL, NULL, NULL, database);
|
|
|
|
/* check to see that the backend connection was successfully made */
|
|
if (PQstatus(conn) != CONNECTION_OK)
|
|
{
|
|
fprintf(stderr, "%s", PQerrorMessage(conn));
|
|
exit_nicely(conn);
|
|
}
|
|
|
|
/* Set always-secure search path, so malicious users can't take control. */
|
|
res = PQexec(conn,
|
|
"SELECT pg_catalog.set_config('search_path', '', false)");
|
|
if (PQresultStatus(res) != PGRES_TUPLES_OK)
|
|
{
|
|
fprintf(stderr, "SET failed: %s", PQerrorMessage(conn));
|
|
PQclear(res);
|
|
exit_nicely(conn);
|
|
}
|
|
PQclear(res);
|
|
|
|
res = PQexec(conn, "begin");
|
|
PQclear(res);
|
|
printf("importing file \"%s\" ...\n", in_filename);
|
|
/* lobjOid = importFile(conn, in_filename); */
|
|
lobjOid = lo_import(conn, in_filename);
|
|
if (lobjOid == 0)
|
|
fprintf(stderr, "%s\n", PQerrorMessage(conn));
|
|
else
|
|
{
|
|
printf("\tas large object %u.\n", lobjOid);
|
|
|
|
printf("picking out bytes 4294967000-4294968000 of the large object\n");
|
|
pickout(conn, lobjOid, 4294967000U, 1000);
|
|
|
|
printf("overwriting bytes 4294967000-4294968000 of the large object with X's\n");
|
|
overwrite(conn, lobjOid, 4294967000U, 1000);
|
|
|
|
printf("exporting large object to file \"%s\" ...\n", out_filename);
|
|
/* exportFile(conn, lobjOid, out_filename); */
|
|
if (lo_export(conn, lobjOid, out_filename) < 0)
|
|
fprintf(stderr, "%s\n", PQerrorMessage(conn));
|
|
|
|
printf("truncating to 3294968000 bytes\n");
|
|
my_truncate(conn, lobjOid, 3294968000U);
|
|
|
|
printf("exporting truncated large object to file \"%s\" ...\n", out_filename2);
|
|
if (lo_export(conn, lobjOid, out_filename2) < 0)
|
|
fprintf(stderr, "%s\n", PQerrorMessage(conn));
|
|
}
|
|
|
|
res = PQexec(conn, "end");
|
|
PQclear(res);
|
|
PQfinish(conn);
|
|
return 0;
|
|
}
|