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