1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-28 05:21:27 +03:00
postgres/src/bin/psql/large_obj.c
Bruce Momjian 92288a1cf9 Change made to elog:
o  Change all current CVS messages of NOTICE to WARNING.  We were going
to do this just before 7.3 beta but it has to be done now, as you will
see below.

o Change current INFO messages that should be controlled by
client_min_messages to NOTICE.

o Force remaining INFO messages, like from EXPLAIN, VACUUM VERBOSE, etc.
to always go to the client.

o Remove INFO from the client_min_messages options and add NOTICE.

Seems we do need three non-ERROR elog levels to handle the various
behaviors we need for these messages.

Regression passed.
2002-03-06 06:10:59 +00:00

377 lines
7.0 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.19 2002/03/06 06:10:31 momjian 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"
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
/*
* 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, "WARNING: ROLLBACK: no transaction in progress\n") != 0) ||
(commit && strcmp(notice, "WARNING: COMMIT: no transaction in progress\n") != 0))
fputs(notice, stderr);
}
else if (!QUIET())
{
if (commit)
puts(gettext("Warning: Your transaction in progress has been committed."));
else
puts(gettext("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)
{
psql_error("\\lo_export: not connected to a database\n");
return false;
}
if (own_transaction)
{
if (!handle_transaction())
return false;
if (!(res = PSQLexec("BEGIN")))
return false;
PQclear(res);
}
status = lo_export(pset.db, atooid(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 oidbuf[32];
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)
{
psql_error("\\lo_import: not connected to a database\n");
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 */
/* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */
if (comment_arg && pset.issuper)
{
char *cmdbuf;
char *bufptr;
int slen = strlen(comment_arg);
cmdbuf = malloc(slen * 2 + 256);
if (!cmdbuf)
{
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
return false;
}
sprintf(cmdbuf,
"INSERT INTO pg_description VALUES ('%u', "
"(SELECT oid FROM pg_class WHERE relname = 'pg_largeobject'),"
" 0, '", loid);
bufptr = cmdbuf + strlen(cmdbuf);
for (i = 0; i < slen; i++)
{
if (comment_arg[i] == '\'' || comment_arg[i] == '\\')
*bufptr++ = '\\';
*bufptr++ = comment_arg[i];
}
strcpy(bufptr, "')");
if (!(res = PSQLexec(cmdbuf)))
{
if (own_transaction)
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
}
free(cmdbuf);
return false;
}
PQclear(res);
free(cmdbuf);
}
if (own_transaction)
{
if (!(res = PSQLexec("COMMIT")))
{
res = PQexec(pset.db, "ROLLBACK");
PQclear(res);
return false;
}
PQclear(res);
}
fprintf(pset.queryFout, "lo_import %u\n", loid);
sprintf(oidbuf, "%u", loid);
SetVariable(pset.vars, "LASTOID", oidbuf);
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 = atooid(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)
{
psql_error("\\lo_unlink: not connected to a database\n");
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 */
/* XXX don't try to hack pg_description if not superuser */
/* XXX ought to replace this with some kind of COMMENT command */
if (pset.issuper)
{
sprintf(buf, "DELETE FROM pg_description WHERE objoid = '%u' "
"AND classoid = (SELECT oid FROM pg_class WHERE relname = 'pg_largeobject')",
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 %u\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;
snprintf(buf, sizeof(buf),
"SELECT loid as \"ID\", obj_description(loid, 'pg_largeobject') as \"%s\"\n"
"FROM (SELECT DISTINCT loid FROM pg_largeobject) x\n"
"ORDER BY \"ID\"",
gettext("Description"));
res = PSQLexec(buf);
if (!res)
return false;
myopt.topt.tuples_only = false;
myopt.nullPrint = NULL;
myopt.title = gettext("Large objects");
printQuery(res, &myopt, pset.queryFout);
PQclear(res);
return true;
}