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 "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
32static void _WriteData(ArchiveHandle *AH, const void *data, size_t dLen);
33static void _WriteBlobData(ArchiveHandle *AH, const void *data, size_t dLen);
34static void _EndData(ArchiveHandle *AH, TocEntry *te);
35static int _WriteByte(ArchiveHandle *AH, const int i);
36static void _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len);
37static void _CloseArchive(ArchiveHandle *AH);
38static void _PrintTocData(ArchiveHandle *AH, TocEntry *te);
39static void _StartBlobs(ArchiveHandle *AH, TocEntry *te);
40static void _StartBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
41static void _EndBlob(ArchiveHandle *AH, TocEntry *te, Oid oid);
42static void _EndBlobs(ArchiveHandle *AH, TocEntry *te);
43
44
45/*
46 * Initializer
47 */
48void
49InitArchiveFmt_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 fatal("this format cannot be read");
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 */
85static void
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 */
97static void
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
116static void
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 */
131static void
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 */
144static void
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 fatal("invalid OID for large object");
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 */
171static void
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 */
184static void
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 */
195static void
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
214static int
215_WriteByte(ArchiveHandle *AH, const int i)
216{
217 /* Don't do anything */
218 return 0;
219}
220
221static void
222_WriteBuf(ArchiveHandle *AH, const void *buf, size_t len)
223{
224 /* Don't do anything */
225 return;
226}
227
228static void
229_CloseArchive(ArchiveHandle *AH)
230{
231 /* Nothing to do */
232}
233