|
12 | 12 | *by PostgreSQL
|
13 | 13 | *
|
14 | 14 | * IDENTIFICATION
|
15 |
| - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.410 2005/06/21 20:45:44 tgl Exp $ |
| 15 | + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.411 2005/06/30 03:02:56 tgl Exp $ |
16 | 16 | *
|
17 | 17 | *-------------------------------------------------------------------------
|
18 | 18 | */
|
@@ -163,7 +163,9 @@ static void selectSourceSchema(const char *schemaName);
|
163 | 163 | staticchar*getFormattedTypeName(Oidoid,OidOptionsopts);
|
164 | 164 | staticchar*myFormatType(constchar*typname,int32typmod);
|
165 | 165 | staticconstchar*fmtQualifiedId(constchar*schema,constchar*id);
|
| 166 | +staticboolhasBlobs(Archive*AH); |
166 | 167 | staticintdumpBlobs(Archive*AH,void*arg);
|
| 168 | +staticintdumpBlobComments(Archive*AH,void*arg); |
167 | 169 | staticvoiddumpDatabase(Archive*AH);
|
168 | 170 | staticvoiddumpEncoding(Archive*AH);
|
169 | 171 | staticconstchar*getAttrName(intattrnum,TableInfo*tblInfo);
|
@@ -344,6 +346,7 @@ main(int argc, char **argv)
|
344 | 346 |
|
345 | 347 | case's':/* dump schema only */
|
346 | 348 | schemaOnly= true;
|
| 349 | +outputBlobs= false; |
347 | 350 | break;
|
348 | 351 |
|
349 | 352 | case'S':/* Username for superuser in plain text
|
@@ -539,16 +542,22 @@ main(int argc, char **argv)
|
539 | 542 | if (!schemaOnly)
|
540 | 543 | getTableData(tblinfo,numTables,oids);
|
541 | 544 |
|
542 |
| -if (outputBlobs) |
| 545 | +if (outputBlobs&&hasBlobs(g_fout)) |
543 | 546 | {
|
544 |
| -/*This is just a placeholder to allow correct sorting of blobs */ |
| 547 | +/*Add placeholders to allow correct sorting of blobs */ |
545 | 548 | DumpableObject*blobobj;
|
546 | 549 |
|
547 | 550 | blobobj= (DumpableObject*)malloc(sizeof(DumpableObject));
|
548 | 551 | blobobj->objType=DO_BLOBS;
|
549 | 552 | blobobj->catId=nilCatalogId;
|
550 | 553 | AssignDumpId(blobobj);
|
551 | 554 | blobobj->name=strdup("BLOBS");
|
| 555 | + |
| 556 | +blobobj= (DumpableObject*)malloc(sizeof(DumpableObject)); |
| 557 | +blobobj->objType=DO_BLOB_COMMENTS; |
| 558 | +blobobj->catId=nilCatalogId; |
| 559 | +AssignDumpId(blobobj); |
| 560 | +blobobj->name=strdup("BLOB COMMENTS"); |
552 | 561 | }
|
553 | 562 |
|
554 | 563 | /*
|
@@ -1313,52 +1322,82 @@ dumpEncoding(Archive *AH)
|
1313 | 1322 | }
|
1314 | 1323 |
|
1315 | 1324 |
|
| 1325 | +/* |
| 1326 | + * hasBlobs: |
| 1327 | + *Test whether database contains any large objects |
| 1328 | + */ |
| 1329 | +staticbool |
| 1330 | +hasBlobs(Archive*AH) |
| 1331 | +{ |
| 1332 | +boolresult; |
| 1333 | +constchar*blobQry; |
| 1334 | +PGresult*res; |
| 1335 | + |
| 1336 | +/* Make sure we are in proper schema */ |
| 1337 | +selectSourceSchema("pg_catalog"); |
| 1338 | + |
| 1339 | +/* Check for BLOB OIDs */ |
| 1340 | +if (AH->remoteVersion >=70100) |
| 1341 | +blobQry="SELECT loid FROM pg_largeobject LIMIT 1"; |
| 1342 | +else |
| 1343 | +blobQry="SELECT oid FROM pg_class WHERE relkind = 'l' LIMIT 1"; |
| 1344 | + |
| 1345 | +res=PQexec(g_conn,blobQry); |
| 1346 | +check_sql_result(res,g_conn,blobQry,PGRES_TUPLES_OK); |
| 1347 | + |
| 1348 | +result=PQntuples(res)>0; |
| 1349 | + |
| 1350 | +PQclear(res); |
| 1351 | + |
| 1352 | +returnresult; |
| 1353 | +} |
| 1354 | + |
1316 | 1355 | /*
|
1317 | 1356 | * dumpBlobs:
|
1318 | 1357 | *dump all blobs
|
1319 |
| - * |
1320 | 1358 | */
|
1321 | 1359 | staticint
|
1322 | 1360 | dumpBlobs(Archive*AH,void*arg)
|
1323 | 1361 | {
|
1324 |
| -PQExpBufferoidQry=createPQExpBuffer(); |
1325 |
| -PQExpBufferoidFetchQry=createPQExpBuffer(); |
| 1362 | +constchar*blobQry; |
| 1363 | +constchar*blobFetchQry; |
1326 | 1364 | PGresult*res;
|
1327 |
| -inti; |
1328 |
| -intloFd; |
1329 | 1365 | charbuf[LOBBUFSIZE];
|
| 1366 | +inti; |
1330 | 1367 | intcnt;
|
1331 |
| -OidblobOid; |
1332 | 1368 |
|
1333 | 1369 | if (g_verbose)
|
1334 | 1370 | write_msg(NULL,"saving large objects\n");
|
1335 | 1371 |
|
1336 | 1372 | /* Make sure we are in proper schema */
|
1337 | 1373 | selectSourceSchema("pg_catalog");
|
1338 | 1374 |
|
1339 |
| -/* Cursor to get all BLOBtables */ |
| 1375 | +/* Cursor to get all BLOBOIDs */ |
1340 | 1376 | if (AH->remoteVersion >=70100)
|
1341 |
| -appendPQExpBuffer(oidQry,"DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"); |
| 1377 | +blobQry="DECLARE bloboid CURSOR FOR SELECT DISTINCT loid FROM pg_largeobject"; |
1342 | 1378 | else
|
1343 |
| -appendPQExpBuffer(oidQry,"DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'"); |
| 1379 | +blobQry="DECLARE bloboid CURSOR FOR SELECT oid FROM pg_class WHERE relkind = 'l'"; |
1344 | 1380 |
|
1345 |
| -res=PQexec(g_conn,oidQry->data); |
1346 |
| -check_sql_result(res,g_conn,oidQry->data,PGRES_COMMAND_OK); |
| 1381 | +res=PQexec(g_conn,blobQry); |
| 1382 | +check_sql_result(res,g_conn,blobQry,PGRES_COMMAND_OK); |
1347 | 1383 |
|
1348 |
| -/*Fetch for cursor */ |
1349 |
| -appendPQExpBuffer(oidFetchQry,"FETCH 1000 IN bloboid"); |
| 1384 | +/*Command to fetch from cursor */ |
| 1385 | +blobFetchQry="FETCH 1000 IN bloboid"; |
1350 | 1386 |
|
1351 | 1387 | do
|
1352 | 1388 | {
|
1353 | 1389 | PQclear(res);
|
1354 | 1390 |
|
1355 | 1391 | /* Do a fetch */
|
1356 |
| -res=PQexec(g_conn,oidFetchQry->data); |
1357 |
| -check_sql_result(res,g_conn,oidFetchQry->data,PGRES_TUPLES_OK); |
| 1392 | +res=PQexec(g_conn,blobFetchQry); |
| 1393 | +check_sql_result(res,g_conn,blobFetchQry,PGRES_TUPLES_OK); |
1358 | 1394 |
|
1359 | 1395 | /* Process the tuples, if any */
|
1360 | 1396 | for (i=0;i<PQntuples(res);i++)
|
1361 | 1397 | {
|
| 1398 | +OidblobOid; |
| 1399 | +intloFd; |
| 1400 | + |
1362 | 1401 | blobOid=atooid(PQgetvalue(res,i,0));
|
1363 | 1402 | /* Open the BLOB */
|
1364 | 1403 | loFd=lo_open(g_conn,blobOid,INV_READ);
|
@@ -1393,8 +1432,81 @@ dumpBlobs(Archive *AH, void *arg)
|
1393 | 1432 |
|
1394 | 1433 | PQclear(res);
|
1395 | 1434 |
|
1396 |
| -destroyPQExpBuffer(oidQry); |
1397 |
| -destroyPQExpBuffer(oidFetchQry); |
| 1435 | +return1; |
| 1436 | +} |
| 1437 | + |
| 1438 | +/* |
| 1439 | + * dumpBlobComments |
| 1440 | + *dump all blob comments |
| 1441 | + * |
| 1442 | + * Since we don't provide any way to be selective about dumping blobs, |
| 1443 | + * there's no need to be selective about their comments either. We put |
| 1444 | + * all the comments into one big TOC entry. |
| 1445 | + */ |
| 1446 | +staticint |
| 1447 | +dumpBlobComments(Archive*AH,void*arg) |
| 1448 | +{ |
| 1449 | +constchar*blobQry; |
| 1450 | +constchar*blobFetchQry; |
| 1451 | +PQExpBuffercommentcmd=createPQExpBuffer(); |
| 1452 | +PGresult*res; |
| 1453 | +inti; |
| 1454 | + |
| 1455 | +if (g_verbose) |
| 1456 | +write_msg(NULL,"saving large object comments\n"); |
| 1457 | + |
| 1458 | +/* Make sure we are in proper schema */ |
| 1459 | +selectSourceSchema("pg_catalog"); |
| 1460 | + |
| 1461 | +/* Cursor to get all BLOB comments */ |
| 1462 | +if (AH->remoteVersion >=70200) |
| 1463 | +blobQry="DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid, 'pg_largeobject') FROM pg_largeobject"; |
| 1464 | +elseif (AH->remoteVersion >=70100) |
| 1465 | +blobQry="DECLARE blobcmt CURSOR FOR SELECT DISTINCT loid, obj_description(loid) FROM pg_largeobject"; |
| 1466 | +else |
| 1467 | +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'"; |
| 1468 | + |
| 1469 | +res=PQexec(g_conn,blobQry); |
| 1470 | +check_sql_result(res,g_conn,blobQry,PGRES_COMMAND_OK); |
| 1471 | + |
| 1472 | +/* Command to fetch from cursor */ |
| 1473 | +blobFetchQry="FETCH 100 IN blobcmt"; |
| 1474 | + |
| 1475 | +do |
| 1476 | +{ |
| 1477 | +PQclear(res); |
| 1478 | + |
| 1479 | +/* Do a fetch */ |
| 1480 | +res=PQexec(g_conn,blobFetchQry); |
| 1481 | +check_sql_result(res,g_conn,blobFetchQry,PGRES_TUPLES_OK); |
| 1482 | + |
| 1483 | +/* Process the tuples, if any */ |
| 1484 | +for (i=0;i<PQntuples(res);i++) |
| 1485 | +{ |
| 1486 | +OidblobOid; |
| 1487 | +char*comment; |
| 1488 | + |
| 1489 | +/* ignore blobs without comments */ |
| 1490 | +if (PQgetisnull(res,i,1)) |
| 1491 | +continue; |
| 1492 | + |
| 1493 | +blobOid=atooid(PQgetvalue(res,i,0)); |
| 1494 | +comment=PQgetvalue(res,i,1); |
| 1495 | + |
| 1496 | +printfPQExpBuffer(commentcmd,"COMMENT ON LARGE OBJECT %u IS ", |
| 1497 | +blobOid); |
| 1498 | +appendStringLiteral(commentcmd,comment, false); |
| 1499 | +appendPQExpBuffer(commentcmd,";\n"); |
| 1500 | + |
| 1501 | +archputs(commentcmd->data,AH); |
| 1502 | +} |
| 1503 | +}while (PQntuples(res)>0); |
| 1504 | + |
| 1505 | +PQclear(res); |
| 1506 | + |
| 1507 | +archputs("\n",AH); |
| 1508 | + |
| 1509 | +destroyPQExpBuffer(commentcmd); |
1398 | 1510 |
|
1399 | 1511 | return1;
|
1400 | 1512 | }
|
@@ -4356,6 +4468,13 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
|
4356 | 4468 | NULL,0,
|
4357 | 4469 | dumpBlobs,NULL);
|
4358 | 4470 | break;
|
| 4471 | +caseDO_BLOB_COMMENTS: |
| 4472 | +ArchiveEntry(fout,dobj->catId,dobj->dumpId, |
| 4473 | +dobj->name,NULL,NULL,"", |
| 4474 | + false,"BLOB COMMENTS","","",NULL, |
| 4475 | +NULL,0, |
| 4476 | +dumpBlobComments,NULL); |
| 4477 | +break; |
4359 | 4478 | }
|
4360 | 4479 | }
|
4361 | 4480 |
|
|