mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Dump comments for large objects.
This commit is contained in:
parent
4714984149
commit
51c58812d9
@ -12,7 +12,7 @@
|
||||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.410 2005/06/21 20:45:44 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.411 2005/06/30 03:02:56 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -163,7 +163,9 @@ static void selectSourceSchema(const char *schemaName);
|
||||
static char *getFormattedTypeName(Oid oid, OidOptions opts);
|
||||
static char *myFormatType(const char *typname, int32 typmod);
|
||||
static const char *fmtQualifiedId(const char *schema, const char *id);
|
||||
static bool hasBlobs(Archive *AH);
|
||||
static int dumpBlobs(Archive *AH, void *arg);
|
||||
static int dumpBlobComments(Archive *AH, void *arg);
|
||||
static void dumpDatabase(Archive *AH);
|
||||
static void dumpEncoding(Archive *AH);
|
||||
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
|
||||
@ -344,6 +346,7 @@ main(int argc, char **argv)
|
||||
|
||||
case 's': /* dump schema only */
|
||||
schemaOnly = true;
|
||||
outputBlobs = false;
|
||||
break;
|
||||
|
||||
case 'S': /* Username for superuser in plain text
|
||||
@ -539,9 +542,9 @@ main(int argc, char **argv)
|
||||
if (!schemaOnly)
|
||||
getTableData(tblinfo, numTables, oids);
|
||||
|
||||
if (outputBlobs)
|
||||
if (outputBlobs && hasBlobs(g_fout))
|
||||
{
|
||||
/* This is just a placeholder to allow correct sorting of blobs */
|
||||
/* Add placeholders to allow correct sorting of blobs */
|
||||
DumpableObject *blobobj;
|
||||
|
||||
blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
|
||||
@ -549,6 +552,12 @@ main(int argc, char **argv)
|
||||
blobobj->catId = nilCatalogId;
|
||||
AssignDumpId(blobobj);
|
||||
blobobj->name = strdup("BLOBS");
|
||||
|
||||
blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
|
||||
blobobj->objType = DO_BLOB_COMMENTS;
|
||||
blobobj->catId = nilCatalogId;
|
||||
AssignDumpId(blobobj);
|
||||
blobobj->name = strdup("BLOB COMMENTS");
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1313,22 +1322,49 @@ dumpEncoding(Archive *AH)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hasBlobs:
|
||||
* Test whether database contains any large objects
|
||||
*/
|
||||
static bool
|
||||
hasBlobs(Archive *AH)
|
||||
{
|
||||
bool result;
|
||||
const char *blobQry;
|
||||
PGresult *res;
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema("pg_catalog");
|
||||
|
||||
/* Check for BLOB OIDs */
|
||||
if (AH->remoteVersion >= 70100)
|
||||
blobQry = "SELECT loid FROM pg_largeobject LIMIT 1";
|
||||
else
|
||||
blobQry = "SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1";
|
||||
|
||||
res = PQexec(g_conn, blobQry);
|
||||
check_sql_result(res, g_conn, blobQry, PGRES_TUPLES_OK);
|
||||
|
||||
result = PQntuples(res) > 0;
|
||||
|
||||
PQclear(res);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* dumpBlobs:
|
||||
* dump all blobs
|
||||
*
|
||||
*/
|
||||
static int
|
||||
dumpBlobs(Archive *AH, void *arg)
|
||||
{
|
||||
PQExpBuffer oidQry = createPQExpBuffer();
|
||||
PQExpBuffer oidFetchQry = createPQExpBuffer();
|
||||
const char *blobQry;
|
||||
const char *blobFetchQry;
|
||||
PGresult *res;
|
||||
int i;
|
||||
int loFd;
|
||||
char buf[LOBBUFSIZE];
|
||||
int i;
|
||||
int cnt;
|
||||
Oid blobOid;
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "saving large objects\n");
|
||||
@ -1336,29 +1372,32 @@ dumpBlobs(Archive *AH, void *arg)
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema("pg_catalog");
|
||||
|
||||
/* Cursor to get all BLOB tables */
|
||||
/* Cursor to get all BLOB OIDs */
|
||||
if (AH->remoteVersion >= 70100)
|
||||
appendPQExpBuffer(oidQry, "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject");
|
||||
blobQry = "DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject";
|
||||
else
|
||||
appendPQExpBuffer(oidQry, "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'");
|
||||
blobQry = "DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'";
|
||||
|
||||
res = PQexec(g_conn, oidQry->data);
|
||||
check_sql_result(res, g_conn, oidQry->data, PGRES_COMMAND_OK);
|
||||
res = PQexec(g_conn, blobQry);
|
||||
check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
|
||||
|
||||
/* Fetch for cursor */
|
||||
appendPQExpBuffer(oidFetchQry, "FETCH 1000 IN bloboid");
|
||||
/* Command to fetch from cursor */
|
||||
blobFetchQry = "FETCH 1000 IN bloboid";
|
||||
|
||||
do
|
||||
{
|
||||
PQclear(res);
|
||||
|
||||
/* Do a fetch */
|
||||
res = PQexec(g_conn, oidFetchQry->data);
|
||||
check_sql_result(res, g_conn, oidFetchQry->data, PGRES_TUPLES_OK);
|
||||
res = PQexec(g_conn, blobFetchQry);
|
||||
check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
|
||||
|
||||
/* Process the tuples, if any */
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
Oid blobOid;
|
||||
int loFd;
|
||||
|
||||
blobOid = atooid(PQgetvalue(res, i, 0));
|
||||
/* Open the BLOB */
|
||||
loFd = lo_open(g_conn, blobOid, INV_READ);
|
||||
@ -1393,8 +1432,81 @@ dumpBlobs(Archive *AH, void *arg)
|
||||
|
||||
PQclear(res);
|
||||
|
||||
destroyPQExpBuffer(oidQry);
|
||||
destroyPQExpBuffer(oidFetchQry);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* dumpBlobComments
|
||||
* dump all blob comments
|
||||
*
|
||||
* Since we don't provide any way to be selective about dumping blobs,
|
||||
* there's no need to be selective about their comments either. We put
|
||||
* all the comments into one big TOC entry.
|
||||
*/
|
||||
static int
|
||||
dumpBlobComments(Archive *AH, void *arg)
|
||||
{
|
||||
const char *blobQry;
|
||||
const char *blobFetchQry;
|
||||
PQExpBuffer commentcmd = createPQExpBuffer();
|
||||
PGresult *res;
|
||||
int i;
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "saving large object comments\n");
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema("pg_catalog");
|
||||
|
||||
/* Cursor to get all BLOB comments */
|
||||
if (AH->remoteVersion >= 70200)
|
||||
blobQry = "DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid, 'pg_largeobject') FROM pg_largeobject";
|
||||
else if (AH->remoteVersion >= 70100)
|
||||
blobQry = "DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid) FROM pg_largeobject";
|
||||
else
|
||||
blobQry = "DECLARE blobcmt CURSOR FOR SELECT oid, (SELECT description FROM pg_description pd WHERE pd.objoid=pc.oid) FROM pg_class pc WHERE relkind = 'l'";
|
||||
|
||||
res = PQexec(g_conn, blobQry);
|
||||
check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
|
||||
|
||||
/* Command to fetch from cursor */
|
||||
blobFetchQry = "FETCH 100 IN blobcmt";
|
||||
|
||||
do
|
||||
{
|
||||
PQclear(res);
|
||||
|
||||
/* Do a fetch */
|
||||
res = PQexec(g_conn, blobFetchQry);
|
||||
check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
|
||||
|
||||
/* Process the tuples, if any */
|
||||
for (i = 0; i < PQntuples(res); i++)
|
||||
{
|
||||
Oid blobOid;
|
||||
char *comment;
|
||||
|
||||
/* ignore blobs without comments */
|
||||
if (PQgetisnull(res, i, 1))
|
||||
continue;
|
||||
|
||||
blobOid = atooid(PQgetvalue(res, i, 0));
|
||||
comment = PQgetvalue(res, i, 1);
|
||||
|
||||
printfPQExpBuffer(commentcmd, "COMMENT ON LARGE OBJECT %u IS ",
|
||||
blobOid);
|
||||
appendStringLiteral(commentcmd, comment, false);
|
||||
appendPQExpBuffer(commentcmd, ";\n");
|
||||
|
||||
archputs(commentcmd->data, AH);
|
||||
}
|
||||
} while (PQntuples(res) > 0);
|
||||
|
||||
PQclear(res);
|
||||
|
||||
archputs("\n", AH);
|
||||
|
||||
destroyPQExpBuffer(commentcmd);
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -4356,6 +4468,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
|
||||
NULL, 0,
|
||||
dumpBlobs, NULL);
|
||||
break;
|
||||
case DO_BLOB_COMMENTS:
|
||||
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
|
||||
dobj->name, NULL, NULL, "",
|
||||
false, "BLOB COMMENTS", "", "", NULL,
|
||||
NULL, 0,
|
||||
dumpBlobComments, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.115 2004/12/31 22:03:08 pgsql Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.116 2005/06/30 03:03:02 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -78,7 +78,8 @@ typedef enum
|
||||
DO_CAST,
|
||||
DO_TABLE_DATA,
|
||||
DO_TABLE_TYPE,
|
||||
DO_BLOBS
|
||||
DO_BLOBS,
|
||||
DO_BLOB_COMMENTS
|
||||
} DumpableObjectType;
|
||||
|
||||
typedef struct _dumpableObject
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.9 2005/02/03 23:38:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.10 2005/06/30 03:03:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -36,16 +36,17 @@ static const int oldObjectTypePriority[] =
|
||||
5, /* DO_CONVERSION */
|
||||
6, /* DO_TABLE */
|
||||
8, /* DO_ATTRDEF */
|
||||
12, /* DO_INDEX */
|
||||
13, /* DO_RULE */
|
||||
14, /* DO_TRIGGER */
|
||||
11, /* DO_CONSTRAINT */
|
||||
15, /* DO_FK_CONSTRAINT */
|
||||
13, /* DO_INDEX */
|
||||
14, /* DO_RULE */
|
||||
15, /* DO_TRIGGER */
|
||||
12, /* DO_CONSTRAINT */
|
||||
16, /* DO_FK_CONSTRAINT */
|
||||
2, /* DO_PROCLANG */
|
||||
2, /* DO_CAST */
|
||||
9, /* DO_TABLE_DATA */
|
||||
7, /* DO_TABLE_TYPE */
|
||||
10 /* DO_BLOBS */
|
||||
10, /* DO_BLOBS */
|
||||
11 /* DO_BLOB_COMMENTS */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -63,16 +64,17 @@ static const int newObjectTypePriority[] =
|
||||
9, /* DO_CONVERSION */
|
||||
10, /* DO_TABLE */
|
||||
12, /* DO_ATTRDEF */
|
||||
16, /* DO_INDEX */
|
||||
17, /* DO_RULE */
|
||||
18, /* DO_TRIGGER */
|
||||
15, /* DO_CONSTRAINT */
|
||||
19, /* DO_FK_CONSTRAINT */
|
||||
17, /* DO_INDEX */
|
||||
18, /* DO_RULE */
|
||||
19, /* DO_TRIGGER */
|
||||
16, /* DO_CONSTRAINT */
|
||||
20, /* DO_FK_CONSTRAINT */
|
||||
2, /* DO_PROCLANG */
|
||||
8, /* DO_CAST */
|
||||
13, /* DO_TABLE_DATA */
|
||||
11, /* DO_TABLE_TYPE */
|
||||
14 /* DO_BLOBS */
|
||||
14, /* DO_BLOBS */
|
||||
15 /* DO_BLOB_COMMENTS */
|
||||
};
|
||||
|
||||
|
||||
@ -1072,6 +1074,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
|
||||
"BLOBS (ID %d)",
|
||||
obj->dumpId);
|
||||
return;
|
||||
case DO_BLOB_COMMENTS:
|
||||
snprintf(buf, bufsize,
|
||||
"BLOB COMMENTS (ID %d)",
|
||||
obj->dumpId);
|
||||
return;
|
||||
}
|
||||
/* shouldn't get here */
|
||||
snprintf(buf, bufsize,
|
||||
|
Loading…
Reference in New Issue
Block a user