postgresql/src/bin/psql/large_obj.c
Tom Lane d08741eab5 Restructure the key include files per recent pghackers discussion: there
are now separate files "postgres.h" and "postgres_fe.h", which are meant
to be the primary include files for backend .c files and frontend .c files
respectively.  By default, only include files meant for frontend use are
installed into the installation include directory.  There is a new make
target 'make install-all-headers' that adds the whole content of the
src/include tree to the installed fileset, for use by people who want to
develop server-side code without keeping the complete source tree on hand.
Cleaned up a whole lot of crufty and inconsistent header inclusions.
2001-02-10 02:31:31 +00:00

347 lines
6.3 KiB
C

/*
* psql - the PostgreSQL interactive terminal
*
* Copyright 2000 by PostgreSQL Global Development Group
*
* $Header: /cvsroot/pgsql/src/bin/psql/large_obj.c,v 1.13 2001/02/10 02:31:28 tgl Exp $
*/
#include "postgres_fe.h"
#include "large_obj.h"
#include "libpq-fe.h"
#include "settings.h"
#include "variables.h"
#include "common.h"
#include "print.h"
/*
* Since all large object ops must be in a transaction, we must do some magic
* here. You can set the variable lo_transaction to one of commit|rollback|
* nothing to get your favourite behaviour regarding any transaction in
* progress. Rollback is default.
*/
static char notice[80];
static void
_my_notice_handler(void *arg, const char *message)
{
(void) arg;
strncpy(notice, message, 79);
notice[79] = '\0';
}
static bool
handle_transaction(void)
{
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
PGresult *res;
bool commit;
PQnoticeProcessor old_notice_hook;
if (var && strcmp(var, "nothing") == 0)
return true;
commit = (var && strcmp(var, "commit") == 0);
notice[0] = '\0';
old_notice_hook = PQsetNoticeProcessor(pset.db, _my_notice_handler, NULL);
res = PSQLexec(commit ? "COMMIT" : "ROLLBACK");
if (!res)
return false;
if (notice[0])
{
if ((!commit && strcmp(notice, "NOTICE: ROLLBACK: no transaction in progress\n") != 0) ||
(commit && strcmp(notice, "NOTICE: COMMIT: no transaction in progress\n") != 0))
fputs(notice, stderr);
}
else if (!QUIET())
{
if (commit)
puts("Warning: Your transaction in progress has been committed.");
else
puts("Warning: Your transaction in progress has been rolled back.");
}
PQsetNoticeProcessor(pset.db, old_notice_hook, NULL);
return true;
}
/*
* do_lo_export()
*
* Write a large object to a file
*/
bool
do_lo_export(const char *loid_arg, const char *filename_arg)
{
PGresult *res;
int status;
bool own_transaction = true;
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset.db)
{
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_export: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
status = lo_export(pset.db, atol(loid_arg), filename_arg);
if (status != 1)
{ /* of course this status is documented
* nowhere :( */
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
if (own_transaction)
{
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_export\n");
return true;
}
/*
* do_lo_import()
*
* Copy large object from file to database
*/
bool
do_lo_import(const char *filename_arg, const char *comment_arg)
{
PGresult *res;
Oid loid;
char buf[1024];
unsigned int i;
bool own_transaction = true;
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset.db)
{
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_import: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
loid = lo_import(pset.db, filename_arg);
if (loid == InvalidOid)
{
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
/* insert description if given */
if (comment_arg)
{
sprintf(buf, "INSERT INTO pg_description VALUES (%u, '", loid);
for (i = 0; i < strlen(comment_arg); i++)
if (comment_arg[i] == '\'')
strcat(buf, "\\'");
else
strncat(buf, &comment_arg[i], 1);
strcat(buf, "')");
if (!(res = PSQLexec(buf)))
{
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
}
if (own_transaction)
{
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_import %d\n", loid);
sprintf(buf, "%u", (unsigned int) loid);
SetVariable(pset.vars, "LASTOID", buf);
return true;
}
/*
* do_lo_unlink()
*
* removes a large object out of the database
*/
bool
do_lo_unlink(const char *loid_arg)
{
PGresult *res;
int status;
Oid loid = (Oid) atol(loid_arg);
char buf[256];
bool own_transaction = true;
const char *var = GetVariable(pset.vars, "LO_TRANSACTION");
if (var && strcmp(var, "nothing") == 0)
own_transaction = false;
if (!pset.db)
{
if (!pset.cur_cmd_interactive)
fprintf(stderr, "%s: ", pset.progname);
fputs("\\lo_unlink: not connected to a database\n", stderr);
return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
status = lo_unlink(pset.db, loid);
if (status == -1)
{
fputs(PQerrorMessage(pset.db), stderr);
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
/* remove the comment as well */
sprintf(buf, "DELETE FROM pg_description WHERE objoid = %u", loid);
if (!(res = PSQLexec(buf)))
{
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
if (own_transaction)
{
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_unlink %d\n", loid);
return true;
}
/*
* do_lo_list()
*
* Show all large objects in database with comments
*/
bool
do_lo_list(void)
{
PGresult *res;
char buf[1024];
printQueryOpt myopt = pset.popt;
strcpy(buf,
"SELECT loid as \"ID\", obj_description(loid) as \"Description\"\n"
"FROM (SELECT DISTINCT loid FROM pg_largeobject) x\n"
"ORDER BY \"ID\"");
res = PSQLexec(buf);
if (!res)
return false;
myopt.topt.tuples_only = false;
myopt.nullPrint = NULL;
myopt.title = "Large objects";
printQuery(res, &myopt, pset.queryFout);
PQclear(res);
return true;
}