1 /*-------------------------------------------------------------------------
2  *
3  * pg_backup_null.c
4  *
5  *	Implementation of an archive that is never saved; it is used by
6  *	pg_dump to output a plain text SQL script instead of saving
7  *	a real archive.
8  *
9  *	See the headers to pg_restore for more details.
10  *
11  * Copyright (c) 2000, Philip Warner
12  *		Rights are granted to use this software in any way so long
13  *		as this notice is not removed.
14  *
15  *	The author is not responsible for loss or damages that may
16  *	result from its use.
17  *
18  *
19  * IDENTIFICATION
20  *		src/bin/pg_dump/pg_backup_null.c
21  *
22  *-------------------------------------------------------------------------
23  */
24 #include "postgres_fe.h"
25 
26 #include "fe_utils/string_utils.h"
27 #include "libpq/libpq-fs.h"
28 #include "pg_backup_archiver.h"
29 #include "pg_backup_utils.h"
30 
31 static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
32 static void _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen);
33 static void _EndData(ArchiveHandle *AH, TocEntry *te);
34 static int	_WriteByte(ArchiveHandle *AH, const int i);
35 static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
36 static void _CloseArchive(ArchiveHandle *AH);
37 static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
38 static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
39 static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
40 static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
41 static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
42 
43 
44 /*
45  *	Initializer
46  */
47 void
InitArchiveFmt_Null(ArchiveHandle * AH)48 InitArchiveFmt_Null(ArchiveHandle *AH)
49 {
50 	/* Assuming static functions, this can be copied for each format. */
51 	AH->WriteDataPtr = _WriteData;
52 	AH->EndDataPtr = _EndData;
53 	AH->WriteBytePtr = _WriteByte;
54 	AH->WriteBufPtr = _WriteBuf;
55 	AH->ClosePtr = _CloseArchive;
56 	AH->ReopenPtr = NULL;
57 	AH->PrintTocDataPtr = _PrintTocData;
58 
59 	AH->StartBlobsPtr = _StartBlobs;
60 	AH->StartBlobPtr = _StartBlob;
61 	AH->EndBlobPtr = _EndBlob;
62 	AH->EndBlobsPtr = _EndBlobs;
63 	AH->ClonePtr = NULL;
64 	AH->DeClonePtr = NULL;
65 
66 	/* Initialize LO buffering */
67 	AH->lo_buf_size = LOBBUFSIZE;
68 	AH->lo_buf = (void *) pg_malloc(LOBBUFSIZE);
69 
70 	/*
71 	 * Now prevent reading...
72 	 */
73 	if (AH->mode == archModeRead)
74 		fatal("this format cannot be read");
75 }
76 
77 /*
78  * - Start a new TOC entry
79  */
80 
81 /*
82  * Called by dumper via archiver from within a data dump routine
83  */
84 static void
_WriteData(ArchiveHandle * AH,const void * data,size_t dLen)85 _WriteData(ArchiveHandle *AH, const void *data, size_t dLen)
86 {
87 	/* Just send it to output, ahwrite() already errors on failure */
88 	ahwrite(data, 1, dLen, AH);
89 }
90 
91 /*
92  * Called by dumper via archiver from within a data dump routine
93  * We substitute this for _WriteData while emitting a BLOB
94  */
95 static void
_WriteBlobData(ArchiveHandle * AH,const void * data,size_t dLen)96 _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen)
97 {
98 	if (dLen > 0)
99 	{
100 		PQExpBuffer buf = createPQExpBuffer();
101 
102 		appendByteaLiteralAHX(buf,
103 							  (const unsigned char *) data,
104 							  dLen,
105 							  AH);
106 
107 		ahprintf(AH, "SELECT pg_catalog.lowrite(0, %s);\n", buf->data);
108 
109 		destroyPQExpBuffer(buf);
110 	}
111 }
112 
113 static void
_EndData(ArchiveHandle * AH,TocEntry * te)114 _EndData(ArchiveHandle *AH, TocEntry *te)
115 {
116 	ahprintf(AH, "\n\n");
117 }
118 
119 /*
120  * Called by the archiver when starting to save all BLOB DATA (not schema).
121  * This routine should save whatever format-specific information is needed
122  * to read the BLOBs back into memory.
123  *
124  * It is called just prior to the dumper's DataDumper routine.
125  *
126  * Optional, but strongly recommended.
127  */
128 static void
_StartBlobs(ArchiveHandle * AH,TocEntry * te)129 _StartBlobs(ArchiveHandle *AH, TocEntry *te)
130 {
131 	ahprintf(AH, "BEGIN;\n\n");
132 }
133 
134 /*
135  * Called by the archiver when the dumper calls StartBlob.
136  *
137  * Mandatory.
138  *
139  * Must save the passed OID for retrieval at restore-time.
140  */
141 static void
_StartBlob(ArchiveHandle * AH,TocEntry * te,Oid oid)142 _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
143 {
144 	bool		old_blob_style = (AH->version < K_VERS_1_12);
145 
146 	if (oid == 0)
147 		fatal("invalid OID for large object");
148 
149 	/* With an old archive we must do drop and create logic here */
150 	if (old_blob_style && AH->public.ropt->dropSchema)
151 		DropBlobIfExists(AH, oid);
152 
153 	if (old_blob_style)
154 		ahprintf(AH, "SELECT pg_catalog.lo_open(pg_catalog.lo_create('%u'), %d);\n",
155 				 oid, INV_WRITE);
156 	else
157 		ahprintf(AH, "SELECT pg_catalog.lo_open('%u', %d);\n",
158 				 oid, INV_WRITE);
159 
160 	AH->WriteDataPtr = _WriteBlobData;
161 }
162 
163 /*
164  * Called by the archiver when the dumper calls EndBlob.
165  *
166  * Optional.
167  */
168 static void
_EndBlob(ArchiveHandle * AH,TocEntry * te,Oid oid)169 _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid)
170 {
171 	AH->WriteDataPtr = _WriteData;
172 
173 	ahprintf(AH, "SELECT pg_catalog.lo_close(0);\n\n");
174 }
175 
176 /*
177  * Called by the archiver when finishing saving all BLOB DATA.
178  *
179  * Optional.
180  */
181 static void
_EndBlobs(ArchiveHandle * AH,TocEntry * te)182 _EndBlobs(ArchiveHandle *AH, TocEntry *te)
183 {
184 	ahprintf(AH, "COMMIT;\n\n");
185 }
186 
187 /*------
188  * Called as part of a RestoreArchive call; for the NULL archive, this
189  * just sends the data for a given TOC entry to the output.
190  *------
191  */
192 static void
_PrintTocData(ArchiveHandle * AH,TocEntry * te)193 _PrintTocData(ArchiveHandle *AH, TocEntry *te)
194 {
195 	if (te->dataDumper)
196 	{
197 		AH->currToc = te;
198 
199 		if (strcmp(te->desc, "BLOBS") == 0)
200 			_StartBlobs(AH, te);
201 
202 		te->dataDumper((Archive *) AH, te->dataDumperArg);
203 
204 		if (strcmp(te->desc, "BLOBS") == 0)
205 			_EndBlobs(AH, te);
206 
207 		AH->currToc = NULL;
208 	}
209 }
210 
211 static int
_WriteByte(ArchiveHandle * AH,const int i)212 _WriteByte(ArchiveHandle *AH, const int i)
213 {
214 	/* Don't do anything */
215 	return 0;
216 }
217 
218 static void
_WriteBuf(ArchiveHandle * AH,const void * buf,size_t len)219 _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
220 {
221 	/* Don't do anything */
222 }
223 
224 static void
_CloseArchive(ArchiveHandle * AH)225 _CloseArchive(ArchiveHandle *AH)
226 {
227 	/* Nothing to do */
228 }
229