mirror of
https://github.com/postgres/postgres.git
synced 2026-03-24 11:23:46 -04:00
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.
347 lines
6.3 KiB
C
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;
|
|
}
|