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 | |
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 |
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 | 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 | */ |
85 | static 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 | */ |
97 | static 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 | |
116 | static 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 | */ |
131 | static 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 | */ |
144 | static 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 | */ |
171 | static 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 | */ |
184 | static 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 | */ |
195 | static 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 | |
214 | static int |
215 | _WriteByte(ArchiveHandle *AH, const int i) |
216 | { |
217 | /* Don't do anything */ |
218 | return 0; |
219 | } |
220 | |
221 | static void |
222 | _WriteBuf(ArchiveHandle *AH, const void *buf, size_t len) |
223 | { |
224 | /* Don't do anything */ |
225 | return; |
226 | } |
227 | |
228 | static void |
229 | _CloseArchive(ArchiveHandle *AH) |
230 | { |
231 | /* Nothing to do */ |
232 | } |
233 | |