mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-30 19:00:29 +08:00
Dump comments for large objects.
This commit is contained in:
parent
4714984149
commit
51c58812d9
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 *getFormattedTypeName(Oid oid, OidOptions opts);
|
||||||
static char *myFormatType(const char *typname, int32 typmod);
|
static char *myFormatType(const char *typname, int32 typmod);
|
||||||
static const char *fmtQualifiedId(const char *schema, const char *id);
|
static const char *fmtQualifiedId(const char *schema, const char *id);
|
||||||
|
static bool hasBlobs(Archive *AH);
|
||||||
static int dumpBlobs(Archive *AH, void *arg);
|
static int dumpBlobs(Archive *AH, void *arg);
|
||||||
|
static int dumpBlobComments(Archive *AH, void *arg);
|
||||||
static void dumpDatabase(Archive *AH);
|
static void dumpDatabase(Archive *AH);
|
||||||
static void dumpEncoding(Archive *AH);
|
static void dumpEncoding(Archive *AH);
|
||||||
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
|
static const char *getAttrName(int attrnum, TableInfo *tblInfo);
|
||||||
@ -344,6 +346,7 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
case 's': /* dump schema only */
|
case 's': /* dump schema only */
|
||||||
schemaOnly = true;
|
schemaOnly = true;
|
||||||
|
outputBlobs = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'S': /* Username for superuser in plain text
|
case 'S': /* Username for superuser in plain text
|
||||||
@ -539,9 +542,9 @@ main(int argc, char **argv)
|
|||||||
if (!schemaOnly)
|
if (!schemaOnly)
|
||||||
getTableData(tblinfo, numTables, oids);
|
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;
|
DumpableObject *blobobj;
|
||||||
|
|
||||||
blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
|
blobobj = (DumpableObject *) malloc(sizeof(DumpableObject));
|
||||||
@ -549,6 +552,12 @@ main(int argc, char **argv)
|
|||||||
blobobj->catId = nilCatalogId;
|
blobobj->catId = nilCatalogId;
|
||||||
AssignDumpId(blobobj);
|
AssignDumpId(blobobj);
|
||||||
blobobj->name = strdup("BLOBS");
|
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:
|
* dumpBlobs:
|
||||||
* dump all blobs
|
* dump all blobs
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
dumpBlobs(Archive *AH, void *arg)
|
dumpBlobs(Archive *AH, void *arg)
|
||||||
{
|
{
|
||||||
PQExpBuffer oidQry = createPQExpBuffer();
|
const char *blobQry;
|
||||||
PQExpBuffer oidFetchQry = createPQExpBuffer();
|
const char *blobFetchQry;
|
||||||
PGresult *res;
|
PGresult *res;
|
||||||
int i;
|
|
||||||
int loFd;
|
|
||||||
char buf[LOBBUFSIZE];
|
char buf[LOBBUFSIZE];
|
||||||
|
int i;
|
||||||
int cnt;
|
int cnt;
|
||||||
Oid blobOid;
|
|
||||||
|
|
||||||
if (g_verbose)
|
if (g_verbose)
|
||||||
write_msg(NULL, "saving large objects\n");
|
write_msg(NULL, "saving large objects\n");
|
||||||
@ -1336,29 +1372,32 @@ dumpBlobs(Archive *AH, void *arg)
|
|||||||
/* Make sure we are in proper schema */
|
/* Make sure we are in proper schema */
|
||||||
selectSourceSchema("pg_catalog");
|
selectSourceSchema("pg_catalog");
|
||||||
|
|
||||||
/* Cursor to get all BLOB tables */
|
/* Cursor to get all BLOB OIDs */
|
||||||
if (AH->remoteVersion >= 70100)
|
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
|
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);
|
res = PQexec(g_conn, blobQry);
|
||||||
check_sql_result(res, g_conn, oidQry->data, PGRES_COMMAND_OK);
|
check_sql_result(res, g_conn, blobQry, PGRES_COMMAND_OK);
|
||||||
|
|
||||||
/* Fetch for cursor */
|
/* Command to fetch from cursor */
|
||||||
appendPQExpBuffer(oidFetchQry, "FETCH 1000 IN bloboid");
|
blobFetchQry = "FETCH 1000 IN bloboid";
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/* Do a fetch */
|
/* Do a fetch */
|
||||||
res = PQexec(g_conn, oidFetchQry->data);
|
res = PQexec(g_conn, blobFetchQry);
|
||||||
check_sql_result(res, g_conn, oidFetchQry->data, PGRES_TUPLES_OK);
|
check_sql_result(res, g_conn, blobFetchQry, PGRES_TUPLES_OK);
|
||||||
|
|
||||||
/* Process the tuples, if any */
|
/* Process the tuples, if any */
|
||||||
for (i = 0; i < PQntuples(res); i++)
|
for (i = 0; i < PQntuples(res); i++)
|
||||||
{
|
{
|
||||||
|
Oid blobOid;
|
||||||
|
int loFd;
|
||||||
|
|
||||||
blobOid = atooid(PQgetvalue(res, i, 0));
|
blobOid = atooid(PQgetvalue(res, i, 0));
|
||||||
/* Open the BLOB */
|
/* Open the BLOB */
|
||||||
loFd = lo_open(g_conn, blobOid, INV_READ);
|
loFd = lo_open(g_conn, blobOid, INV_READ);
|
||||||
@ -1393,8 +1432,81 @@ dumpBlobs(Archive *AH, void *arg)
|
|||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
destroyPQExpBuffer(oidQry);
|
return 1;
|
||||||
destroyPQExpBuffer(oidFetchQry);
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -4356,6 +4468,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
|
|||||||
NULL, 0,
|
NULL, 0,
|
||||||
dumpBlobs, NULL);
|
dumpBlobs, NULL);
|
||||||
break;
|
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) 1996-2005, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* 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_CAST,
|
||||||
DO_TABLE_DATA,
|
DO_TABLE_DATA,
|
||||||
DO_TABLE_TYPE,
|
DO_TABLE_TYPE,
|
||||||
DO_BLOBS
|
DO_BLOBS,
|
||||||
|
DO_BLOB_COMMENTS
|
||||||
} DumpableObjectType;
|
} DumpableObjectType;
|
||||||
|
|
||||||
typedef struct _dumpableObject
|
typedef struct _dumpableObject
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 */
|
5, /* DO_CONVERSION */
|
||||||
6, /* DO_TABLE */
|
6, /* DO_TABLE */
|
||||||
8, /* DO_ATTRDEF */
|
8, /* DO_ATTRDEF */
|
||||||
12, /* DO_INDEX */
|
13, /* DO_INDEX */
|
||||||
13, /* DO_RULE */
|
14, /* DO_RULE */
|
||||||
14, /* DO_TRIGGER */
|
15, /* DO_TRIGGER */
|
||||||
11, /* DO_CONSTRAINT */
|
12, /* DO_CONSTRAINT */
|
||||||
15, /* DO_FK_CONSTRAINT */
|
16, /* DO_FK_CONSTRAINT */
|
||||||
2, /* DO_PROCLANG */
|
2, /* DO_PROCLANG */
|
||||||
2, /* DO_CAST */
|
2, /* DO_CAST */
|
||||||
9, /* DO_TABLE_DATA */
|
9, /* DO_TABLE_DATA */
|
||||||
7, /* DO_TABLE_TYPE */
|
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 */
|
9, /* DO_CONVERSION */
|
||||||
10, /* DO_TABLE */
|
10, /* DO_TABLE */
|
||||||
12, /* DO_ATTRDEF */
|
12, /* DO_ATTRDEF */
|
||||||
16, /* DO_INDEX */
|
17, /* DO_INDEX */
|
||||||
17, /* DO_RULE */
|
18, /* DO_RULE */
|
||||||
18, /* DO_TRIGGER */
|
19, /* DO_TRIGGER */
|
||||||
15, /* DO_CONSTRAINT */
|
16, /* DO_CONSTRAINT */
|
||||||
19, /* DO_FK_CONSTRAINT */
|
20, /* DO_FK_CONSTRAINT */
|
||||||
2, /* DO_PROCLANG */
|
2, /* DO_PROCLANG */
|
||||||
8, /* DO_CAST */
|
8, /* DO_CAST */
|
||||||
13, /* DO_TABLE_DATA */
|
13, /* DO_TABLE_DATA */
|
||||||
11, /* DO_TABLE_TYPE */
|
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)",
|
"BLOBS (ID %d)",
|
||||||
obj->dumpId);
|
obj->dumpId);
|
||||||
return;
|
return;
|
||||||
|
case DO_BLOB_COMMENTS:
|
||||||
|
snprintf(buf, bufsize,
|
||||||
|
"BLOB COMMENTS (ID %d)",
|
||||||
|
obj->dumpId);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
/* shouldn't get here */
|
/* shouldn't get here */
|
||||||
snprintf(buf, bufsize,
|
snprintf(buf, bufsize,
|
||||||
|
Loading…
Reference in New Issue
Block a user