1818 *
1919 * Modifications - 28-Jun-2000 - pjw@rhyme.com.au
2020 *
21- *Initial version.
21+ *Initial version.
22+ *
23+ * Modifications - 31-Jul-2000 - pjw@rhyme.com.au (1.46, 1.47)
24+ *Fixed version number initialization in _allocAH (pg_backup_archiver.c)
2225 *
2326 *-------------------------------------------------------------------------
2427 */
@@ -43,7 +46,9 @@ static int_tocSortCompareByIDNum(const void *p1, const void *p2);
4346static ArchiveHandle * _allocAH (const char * FileSpec ,const ArchiveFormat fmt ,
4447int compression ,ArchiveMode mode );
4548static int _printTocEntry (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt );
46- static void _reconnectAsOwner (ArchiveHandle * AH ,TocEntry * te );
49+
50+ static void _reconnectAsOwner (ArchiveHandle * AH ,const char * dbname ,TocEntry * te );
51+ static void _reconnectAsUser (ArchiveHandle * AH ,const char * dbname ,char * user );
4752
4853static int _tocEntryRequired (TocEntry * te ,RestoreOptions * ropt );
4954static void _disableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt );
@@ -58,7 +63,7 @@ static char*progname = "Archiver";
5863static void _die_horribly (ArchiveHandle * AH ,const char * fmt ,va_list ap );
5964
6065static int _canRestoreBlobs (ArchiveHandle * AH );
61-
66+ static int _restoringToDB ( ArchiveHandle * AH );
6267
6368/*
6469 * Wrapper functions.
@@ -110,6 +115,9 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
110115
111116AH -> ropt = ropt ;
112117
118+ if (ropt -> create && ropt -> noReconnect )
119+ die_horribly (AH ,"%s: --create and --no-reconnect are incompatible options\n" ,progname );
120+
113121/*
114122 * If we're using a DB connection, then connect it.
115123 */
@@ -121,8 +129,25 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
121129
122130ConnectDatabase (AHX ,ropt -> dbname ,ropt -> pghost ,ropt -> pgport ,
123131ropt -> requirePassword ,ropt -> ignoreVersion );
132+
133+ /*
134+ * If no superuser was specified then see if the current user will do...
135+ */
136+ if (!ropt -> superuser )
137+ {
138+ if (UserIsSuperuser (AH ,ConnectedUser (AH )))
139+ ropt -> superuser = strdup (ConnectedUser (AH ));
140+ }
141+
124142}
125143
144+ if (!ropt -> superuser )
145+ fprintf (stderr ,"\n%s: ******** WARNING ******** \n"
146+ " Data restoration may fail since any defined triggers\n"
147+ " can not be disabled (no superuser username specified).\n"
148+ " This is only a problem for restoration into a database\n"
149+ " with triggers already defined.\n\n" ,progname );
150+
126151/*
127152 *Setup the output file if necessary.
128153 */
@@ -155,16 +180,20 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
155180/* Work out what, if anything, we want from this entry */
156181reqs = _tocEntryRequired (te ,ropt );
157182
158- /* Reconnect if necessary */
159- if (reqs != 0 )
160- {
161- _reconnectAsOwner (AH ,te );
162- }
163-
164183if ( (reqs & 1 )!= 0 )/* We want the schema */
165184{
185+ /* Reconnect if necessary */
186+ _reconnectAsOwner (AH ,"-" ,te );
187+
166188ahlog (AH ,1 ,"Creating %s %s\n" ,te -> desc ,te -> name );
167189_printTocEntry (AH ,te ,ropt );
190+
191+ /* If we created a DB, connect to it... */
192+ if (strcmp (te -> desc ,"DATABASE" )== 0 )
193+ {
194+ ahlog (AH ,1 ,"Connecting to new DB '%s' as %s\n" ,te -> name ,te -> owner );
195+ _reconnectAsUser (AH ,te -> name ,te -> owner );
196+ }
168197}
169198
170199/*
@@ -176,8 +205,6 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
176205die_horribly (AH ,"%s: Unable to restore data from a compressed archive\n" ,progname );
177206#endif
178207
179- ahlog (AH ,1 ,"Restoring data for %s \n" ,te -> name );
180-
181208ahprintf (AH ,"--\n-- Data for TOC Entry ID %d (OID %s) %s %s\n--\n\n" ,
182209te -> id ,te -> oid ,te -> desc ,te -> name );
183210
@@ -197,6 +224,10 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
197224
198225_disableTriggers (AH ,te ,ropt );
199226
227+ /* Reconnect if necessary (_disableTriggers may have reconnected) */
228+ _reconnectAsOwner (AH ,"-" ,te );
229+
230+ ahlog (AH ,1 ,"Restoring data for %s \n" ,te -> name );
200231
201232/* If we have a copy statement, use it. As of V1.3, these are separate
202233 * to allow easy import from withing a database connection. Pre 1.3
@@ -256,6 +287,12 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
256287{
257288PQfinish (AH -> connection );
258289AH -> connection = NULL ;
290+
291+ if (AH -> blobConnection )
292+ {
293+ PQfinish (AH -> blobConnection );
294+ AH -> blobConnection = NULL ;
295+ }
259296}
260297}
261298
@@ -274,19 +311,89 @@ RestoreOptions*NewRestoreOptions(void)
274311return opts ;
275312}
276313
277- static int _canRestoreBlobs (ArchiveHandle * AH )
314+ static int _restoringToDB (ArchiveHandle * AH )
278315{
279316return (AH -> ropt -> useDB && AH -> connection );
280317}
281318
319+ static int _canRestoreBlobs (ArchiveHandle * AH )
320+ {
321+ return _restoringToDB (AH );
322+ }
323+
282324static void _disableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )
283325{
326+ char * oldUser = NULL ;
327+
328+ /* Can't do much if we're connected & don't have a superuser */
329+ if (_restoringToDB (AH )&& !ropt -> superuser )
330+ return ;
331+
332+ /*
333+ * Reconnect as superuser if possible, since they are the only ones
334+ * who can update pg_class...
335+ */
336+ if (ropt -> superuser )
337+ {
338+ /* If we're not allowing changes for ownership, then remember the user
339+ * so we can change it back here. Otherwise, let _reconnectAsOwner
340+ * do what it has to do.
341+ */
342+ if (ropt -> noOwner )
343+ oldUser = strdup (ConnectedUser (AH ));
344+ _reconnectAsUser (AH ,"-" ,ropt -> superuser );
345+ }
346+
347+ ahlog (AH ,1 ,"Disabling triggers\n" );
348+
349+ /*
350+ * Disable them. This is a hack. Needs to be done via an appropriate 'SET'
351+ * command when one is available.
352+ */
284353ahprintf (AH ,"-- Disable triggers\n" );
285354ahprintf (AH ,"UPDATE \"pg_class\" SET \"reltriggers\" = 0 WHERE \"relname\" !~ '^pg_';\n\n" );
355+
356+ /*
357+ * Restore the user connection from the start of this procedure
358+ * if _reconnectAsOwner is disabled.
359+ */
360+ if (ropt -> noOwner && oldUser )
361+ {
362+ _reconnectAsUser (AH ,"-" ,oldUser );
363+ free (oldUser );
364+ }
286365}
287366
288367static void _enableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )
289368{
369+ char * oldUser = NULL ;
370+
371+ /* Can't do much if we're connected & don't have a superuser */
372+ if (_restoringToDB (AH )&& !ropt -> superuser )
373+ return ;
374+
375+ /*
376+ * Reconnect as superuser if possible, since they are the only ones
377+ * who can update pg_class...
378+ */
379+ if (ropt -> superuser )
380+ {
381+ /* If we're not allowing changes for ownership, then remember the user
382+ * so we can change it back here. Otherwise, let _reconnectAsOwner
383+ * do what it has to do
384+ */
385+ if (ropt -> noOwner )
386+ oldUser = strdup (ConnectedUser (AH ));
387+
388+ _reconnectAsUser (AH ,"-" ,ropt -> superuser );
389+ }
390+
391+ ahlog (AH ,1 ,"Enabling triggers\n" );
392+
393+ /*
394+ * Enable them. This is a hack. Needs to be done via an appropriate 'SET'
395+ * command when one is available.
396+ */
290397ahprintf (AH ,"-- Enable triggers\n" );
291398ahprintf (AH ,"BEGIN TRANSACTION;\n" );
292399ahprintf (AH ,"CREATE TEMP TABLE \"tr\" (\"tmp_relname\" name, \"tmp_reltriggers\" smallint);\n" );
@@ -298,8 +405,17 @@ static void _enableTriggers(ArchiveHandle *AH, TocEntry *te, RestoreOptions *rop
298405"\"pg_class\".\"relname\" = TMP.\"tmp_relname\";\n" );
299406ahprintf (AH ,"DROP TABLE \"tr\";\n" );
300407ahprintf (AH ,"COMMIT TRANSACTION;\n\n" );
301- }
302408
409+ /*
410+ * Restore the user connection from the start of this procedure
411+ * if _reconnectAsOwner is disabled.
412+ */
413+ if (ropt -> noOwner && oldUser )
414+ {
415+ _reconnectAsUser (AH ,"-" ,oldUser );
416+ free (oldUser );
417+ }
418+ }
303419
304420/*
305421 * This is a routine that is part of the dumper interface, hence the 'Archive*' parameter.
@@ -394,6 +510,8 @@ void PrintTOCSummary(Archive* AHX, RestoreOptions *ropt)
394510default :
395511fmtName = "UNKNOWN" ;
396512}
513+
514+ ahprintf (AH ,"; Dump Version: %d.%d-%d\n" ,AH -> vmaj ,AH -> vmin ,AH -> vrev );
397515ahprintf (AH ,"; Format: %s\n;\n" ,fmtName );
398516
399517ahprintf (AH ,";\n; Selected TOC Entries:\n;\n" );
@@ -456,14 +574,14 @@ void StartRestoreBlob(ArchiveHandle* AH, int oid)
456574AH -> createdBlobXref = 1 ;
457575}
458576
577+ StartTransaction (AH );
578+
459579loOid = lo_creat (AH -> connection ,INV_READ |INV_WRITE );
460580if (loOid == 0 )
461581die_horribly (AH ,"%s: unable to create BLOB\n" ,progname );
462582
463583ahlog (AH ,1 ,"Restoring BLOB oid %d as %d\n" ,oid ,loOid );
464584
465- StartTransaction (AH );
466-
467585InsertBlobXref (AH ,oid ,loOid );
468586
469587AH -> loFd = lo_open (AH -> connection ,loOid ,INV_WRITE );
@@ -829,6 +947,8 @@ static void _die_horribly(ArchiveHandle *AH, const char *fmt, va_list ap)
829947if (AH )
830948if (AH -> connection )
831949PQfinish (AH -> connection );
950+ if (AH -> blobConnection )
951+ PQfinish (AH -> blobConnection );
832952
833953exit (1 );
834954}
@@ -1113,6 +1233,7 @@ static ArchiveHandle* _allocAH(const char* FileSpec, const ArchiveFormat fmt,
11131233
11141234AH -> vmaj = K_VERS_MAJOR ;
11151235AH -> vmin = K_VERS_MINOR ;
1236+ AH -> vrev = K_VERS_REV ;
11161237
11171238AH -> createDate = time (NULL );
11181239
@@ -1299,6 +1420,9 @@ static int _tocEntryRequired(TocEntry* te, RestoreOptions *ropt)
12991420if (ropt -> aclsSkip && strcmp (te -> desc ,"ACL" )== 0 )
13001421return 0 ;
13011422
1423+ if (!ropt -> create && strcmp (te -> desc ,"DATABASE" )== 0 )
1424+ return 0 ;
1425+
13021426/* Check if tablename only is wanted */
13031427if (ropt -> selTypes )
13041428 {
@@ -1351,20 +1475,32 @@ static int _tocEntryRequired(TocEntry* te, RestoreOptions *ropt)
13511475return res ;
13521476}
13531477
1354- static void _reconnectAsOwner (ArchiveHandle * AH ,TocEntry * te )
1478+ static void _reconnectAsUser (ArchiveHandle * AH ,const char * dbname , char * user )
13551479{
1356- if (te -> owner && strlen (te -> owner )!= 0 && strcmp (AH -> currUser ,te -> owner )!= 0 ) {
1480+ if (AH -> ropt && AH -> ropt -> noReconnect )
1481+ return ;
1482+
1483+ if (user && strlen (user )!= 0
1484+ && ( (strcmp (AH -> currUser ,user )!= 0 )|| (strcmp (dbname ,"-" )!= 0 )))
1485+ {
13571486if (RestoringToDB (AH ))
13581487{
1359- ReconnectDatabase (AH ,te -> owner );
1360- /* todo pjw - ???? fix for db connection... */
1488+ ReconnectDatabase (AH ,dbname ,user );
13611489}
13621490else
13631491{
1364- ahprintf (AH ,"\\connect- %s\n" ,te -> owner );
1492+ ahprintf (AH ,"\\connect%s %s\n" ,dbname , user );
13651493}
1366- AH -> currUser = te -> owner ;
1367- }
1494+ AH -> currUser = user ;
1495+ }
1496+ }
1497+
1498+ static void _reconnectAsOwner (ArchiveHandle * AH ,const char * dbname ,TocEntry * te )
1499+ {
1500+ if (AH -> ropt && AH -> ropt -> noOwner )
1501+ return ;
1502+
1503+ _reconnectAsUser (AH ,dbname ,te -> owner );
13681504}
13691505
13701506static int _printTocEntry (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )