| 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 | |