18
18
*
19
19
* Modifications - 28-Jun-2000 - pjw@rhyme.com.au
20
20
*
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)
22
25
*
23
26
*-------------------------------------------------------------------------
24
27
*/
@@ -43,7 +46,9 @@ static int_tocSortCompareByIDNum(const void *p1, const void *p2);
43
46
static ArchiveHandle * _allocAH (const char * FileSpec ,const ArchiveFormat fmt ,
44
47
int compression ,ArchiveMode mode );
45
48
static 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 );
47
52
48
53
static int _tocEntryRequired (TocEntry * te ,RestoreOptions * ropt );
49
54
static void _disableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt );
@@ -58,7 +63,7 @@ static char*progname = "Archiver";
58
63
static void _die_horribly (ArchiveHandle * AH ,const char * fmt ,va_list ap );
59
64
60
65
static int _canRestoreBlobs (ArchiveHandle * AH );
61
-
66
+ static int _restoringToDB ( ArchiveHandle * AH );
62
67
63
68
/*
64
69
* Wrapper functions.
@@ -110,6 +115,9 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
110
115
111
116
AH -> ropt = ropt ;
112
117
118
+ if (ropt -> create && ropt -> noReconnect )
119
+ die_horribly (AH ,"%s: --create and --no-reconnect are incompatible options\n" ,progname );
120
+
113
121
/*
114
122
* If we're using a DB connection, then connect it.
115
123
*/
@@ -121,8 +129,25 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
121
129
122
130
ConnectDatabase (AHX ,ropt -> dbname ,ropt -> pghost ,ropt -> pgport ,
123
131
ropt -> 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
+
124
142
}
125
143
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
+
126
151
/*
127
152
*Setup the output file if necessary.
128
153
*/
@@ -155,16 +180,20 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
155
180
/* Work out what, if anything, we want from this entry */
156
181
reqs = _tocEntryRequired (te ,ropt );
157
182
158
- /* Reconnect if necessary */
159
- if (reqs != 0 )
160
- {
161
- _reconnectAsOwner (AH ,te );
162
- }
163
-
164
183
if ( (reqs & 1 )!= 0 )/* We want the schema */
165
184
{
185
+ /* Reconnect if necessary */
186
+ _reconnectAsOwner (AH ,"-" ,te );
187
+
166
188
ahlog (AH ,1 ,"Creating %s %s\n" ,te -> desc ,te -> name );
167
189
_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
+ }
168
197
}
169
198
170
199
/*
@@ -176,8 +205,6 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
176
205
die_horribly (AH ,"%s: Unable to restore data from a compressed archive\n" ,progname );
177
206
#endif
178
207
179
- ahlog (AH ,1 ,"Restoring data for %s \n" ,te -> name );
180
-
181
208
ahprintf (AH ,"--\n-- Data for TOC Entry ID %d (OID %s) %s %s\n--\n\n" ,
182
209
te -> id ,te -> oid ,te -> desc ,te -> name );
183
210
@@ -197,6 +224,10 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
197
224
198
225
_disableTriggers (AH ,te ,ropt );
199
226
227
+ /* Reconnect if necessary (_disableTriggers may have reconnected) */
228
+ _reconnectAsOwner (AH ,"-" ,te );
229
+
230
+ ahlog (AH ,1 ,"Restoring data for %s \n" ,te -> name );
200
231
201
232
/* If we have a copy statement, use it. As of V1.3, these are separate
202
233
* to allow easy import from withing a database connection. Pre 1.3
@@ -256,6 +287,12 @@ void RestoreArchive(Archive* AHX, RestoreOptions *ropt)
256
287
{
257
288
PQfinish (AH -> connection );
258
289
AH -> connection = NULL ;
290
+
291
+ if (AH -> blobConnection )
292
+ {
293
+ PQfinish (AH -> blobConnection );
294
+ AH -> blobConnection = NULL ;
295
+ }
259
296
}
260
297
}
261
298
@@ -274,19 +311,89 @@ RestoreOptions*NewRestoreOptions(void)
274
311
return opts ;
275
312
}
276
313
277
- static int _canRestoreBlobs (ArchiveHandle * AH )
314
+ static int _restoringToDB (ArchiveHandle * AH )
278
315
{
279
316
return (AH -> ropt -> useDB && AH -> connection );
280
317
}
281
318
319
+ static int _canRestoreBlobs (ArchiveHandle * AH )
320
+ {
321
+ return _restoringToDB (AH );
322
+ }
323
+
282
324
static void _disableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )
283
325
{
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
+ */
284
353
ahprintf (AH ,"-- Disable triggers\n" );
285
354
ahprintf (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
+ }
286
365
}
287
366
288
367
static void _enableTriggers (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )
289
368
{
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
+ */
290
397
ahprintf (AH ,"-- Enable triggers\n" );
291
398
ahprintf (AH ,"BEGIN TRANSACTION;\n" );
292
399
ahprintf (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
298
405
"\"pg_class\".\"relname\" = TMP.\"tmp_relname\";\n" );
299
406
ahprintf (AH ,"DROP TABLE \"tr\";\n" );
300
407
ahprintf (AH ,"COMMIT TRANSACTION;\n\n" );
301
- }
302
408
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
+ }
303
419
304
420
/*
305
421
* 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)
394
510
default :
395
511
fmtName = "UNKNOWN" ;
396
512
}
513
+
514
+ ahprintf (AH ,"; Dump Version: %d.%d-%d\n" ,AH -> vmaj ,AH -> vmin ,AH -> vrev );
397
515
ahprintf (AH ,"; Format: %s\n;\n" ,fmtName );
398
516
399
517
ahprintf (AH ,";\n; Selected TOC Entries:\n;\n" );
@@ -456,14 +574,14 @@ void StartRestoreBlob(ArchiveHandle* AH, int oid)
456
574
AH -> createdBlobXref = 1 ;
457
575
}
458
576
577
+ StartTransaction (AH );
578
+
459
579
loOid = lo_creat (AH -> connection ,INV_READ |INV_WRITE );
460
580
if (loOid == 0 )
461
581
die_horribly (AH ,"%s: unable to create BLOB\n" ,progname );
462
582
463
583
ahlog (AH ,1 ,"Restoring BLOB oid %d as %d\n" ,oid ,loOid );
464
584
465
- StartTransaction (AH );
466
-
467
585
InsertBlobXref (AH ,oid ,loOid );
468
586
469
587
AH -> loFd = lo_open (AH -> connection ,loOid ,INV_WRITE );
@@ -829,6 +947,8 @@ static void _die_horribly(ArchiveHandle *AH, const char *fmt, va_list ap)
829
947
if (AH )
830
948
if (AH -> connection )
831
949
PQfinish (AH -> connection );
950
+ if (AH -> blobConnection )
951
+ PQfinish (AH -> blobConnection );
832
952
833
953
exit (1 );
834
954
}
@@ -1113,6 +1233,7 @@ static ArchiveHandle* _allocAH(const char* FileSpec, const ArchiveFormat fmt,
1113
1233
1114
1234
AH -> vmaj = K_VERS_MAJOR ;
1115
1235
AH -> vmin = K_VERS_MINOR ;
1236
+ AH -> vrev = K_VERS_REV ;
1116
1237
1117
1238
AH -> createDate = time (NULL );
1118
1239
@@ -1299,6 +1420,9 @@ static int _tocEntryRequired(TocEntry* te, RestoreOptions *ropt)
1299
1420
if (ropt -> aclsSkip && strcmp (te -> desc ,"ACL" )== 0 )
1300
1421
return 0 ;
1301
1422
1423
+ if (!ropt -> create && strcmp (te -> desc ,"DATABASE" )== 0 )
1424
+ return 0 ;
1425
+
1302
1426
/* Check if tablename only is wanted */
1303
1427
if (ropt -> selTypes )
1304
1428
{
@@ -1351,20 +1475,32 @@ static int _tocEntryRequired(TocEntry* te, RestoreOptions *ropt)
1351
1475
return res ;
1352
1476
}
1353
1477
1354
- static void _reconnectAsOwner (ArchiveHandle * AH ,TocEntry * te )
1478
+ static void _reconnectAsUser (ArchiveHandle * AH ,const char * dbname , char * user )
1355
1479
{
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
+ {
1357
1486
if (RestoringToDB (AH ))
1358
1487
{
1359
- ReconnectDatabase (AH ,te -> owner );
1360
- /* todo pjw - ???? fix for db connection... */
1488
+ ReconnectDatabase (AH ,dbname ,user );
1361
1489
}
1362
1490
else
1363
1491
{
1364
- ahprintf (AH ,"\\connect- %s\n" ,te -> owner );
1492
+ ahprintf (AH ,"\\connect%s %s\n" ,dbname , user );
1365
1493
}
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 );
1368
1504
}
1369
1505
1370
1506
static int _printTocEntry (ArchiveHandle * AH ,TocEntry * te ,RestoreOptions * ropt )