1 /*------------------------------------------------------------------------- 2 * 3 * testlo.c 4 * test using large objects with libpq 5 * 6 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group 7 * Portions Copyright (c) 1994, Regents of the University of California 8 * 9 * 10 * IDENTIFICATION 11 * src/test/examples/testlo.c 12 * 13 *------------------------------------------------------------------------- 14 */ 15 #include <stdio.h> 16 #include <stdlib.h> 17 18 #include <sys/types.h> 19 #include <sys/stat.h> 20 #include <fcntl.h> 21 #include <unistd.h> 22 23 #include "libpq-fe.h" 24 #include "libpq/libpq-fs.h" 25 26 #define BUFSIZE 1024 27 28 /* 29 * importFile - 30 * import file "in_filename" into database as large object "lobjOid" 31 * 32 */ 33 static Oid 34 importFile(PGconn *conn, char *filename) 35 { 36 Oid lobjId; 37 int lobj_fd; 38 char buf[BUFSIZE]; 39 int nbytes, 40 tmp; 41 int fd; 42 43 /* 44 * open the file to be read in 45 */ 46 fd = open(filename, O_RDONLY, 0666); 47 if (fd < 0) 48 { /* error */ 49 fprintf(stderr, "cannot open unix file\"%s\"\n", filename); 50 } 51 52 /* 53 * create the large object 54 */ 55 lobjId = lo_creat(conn, INV_READ | INV_WRITE); 56 if (lobjId == 0) 57 fprintf(stderr, "cannot create large object"); 58 59 lobj_fd = lo_open(conn, lobjId, INV_WRITE); 60 61 /* 62 * read in from the Unix file and write to the inversion file 63 */ 64 while ((nbytes = read(fd, buf, BUFSIZE)) > 0) 65 { 66 tmp = lo_write(conn, lobj_fd, buf, nbytes); 67 if (tmp < nbytes) 68 fprintf(stderr, "error while reading \"%s\"", filename); 69 } 70 71 close(fd); 72 lo_close(conn, lobj_fd); 73 74 return lobjId; 75 } 76 77 static void 78 pickout(PGconn *conn, Oid lobjId, int start, int len) 79 { 80 int lobj_fd; 81 char *buf; 82 int nbytes; 83 int nread; 84 85 lobj_fd = lo_open(conn, lobjId, INV_READ); 86 if (lobj_fd < 0) 87 fprintf(stderr, "cannot open large object %u", lobjId); 88 89 lo_lseek(conn, lobj_fd, start, SEEK_SET); 90 buf = malloc(len + 1); 91 92 nread = 0; 93 while (len - nread > 0) 94 { 95 nbytes = lo_read(conn, lobj_fd, buf, len - nread); 96 buf[nbytes] = '\0'; 97 fprintf(stderr, ">>> %s", buf); 98 nread += nbytes; 99 if (nbytes <= 0) 100 break; /* no more data? */ 101 } 102 free(buf); 103 fprintf(stderr, "\n"); 104 lo_close(conn, lobj_fd); 105 } 106 107 static void 108 overwrite(PGconn *conn, Oid lobjId, int start, int len) 109 { 110 int lobj_fd; 111 char *buf; 112 int nbytes; 113 int nwritten; 114 int i; 115 116 lobj_fd = lo_open(conn, lobjId, INV_WRITE); 117 if (lobj_fd < 0) 118 fprintf(stderr, "cannot open large object %u", lobjId); 119 120 lo_lseek(conn, lobj_fd, start, SEEK_SET); 121 buf = malloc(len + 1); 122 123 for (i = 0; i < len; i++) 124 buf[i] = 'X'; 125 buf[i] = '\0'; 126 127 nwritten = 0; 128 while (len - nwritten > 0) 129 { 130 nbytes = lo_write(conn, lobj_fd, buf + nwritten, len - nwritten); 131 nwritten += nbytes; 132 if (nbytes <= 0) 133 { 134 fprintf(stderr, "\nWRITE FAILED!\n"); 135 break; 136 } 137 } 138 free(buf); 139 fprintf(stderr, "\n"); 140 lo_close(conn, lobj_fd); 141 } 142 143 144 /* 145 * exportFile - 146 * export large object "lobjOid" to file "out_filename" 147 * 148 */ 149 static void 150 exportFile(PGconn *conn, Oid lobjId, char *filename) 151 { 152 int lobj_fd; 153 char buf[BUFSIZE]; 154 int nbytes, 155 tmp; 156 int fd; 157 158 /* 159 * open the large object 160 */ 161 lobj_fd = lo_open(conn, lobjId, INV_READ); 162 if (lobj_fd < 0) 163 fprintf(stderr, "cannot open large object %u", lobjId); 164 165 /* 166 * open the file to be written to 167 */ 168 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666); 169 if (fd < 0) 170 { /* error */ 171 fprintf(stderr, "cannot open unix file\"%s\"", 172 filename); 173 } 174 175 /* 176 * read in from the inversion file and write to the Unix file 177 */ 178 while ((nbytes = lo_read(conn, lobj_fd, buf, BUFSIZE)) > 0) 179 { 180 tmp = write(fd, buf, nbytes); 181 if (tmp < nbytes) 182 { 183 fprintf(stderr, "error while writing \"%s\"", 184 filename); 185 } 186 } 187 188 lo_close(conn, lobj_fd); 189 close(fd); 190 191 return; 192 } 193 194 static void 195 exit_nicely(PGconn *conn) 196 { 197 PQfinish(conn); 198 exit(1); 199 } 200 201 int 202 main(int argc, char **argv) 203 { 204 char *in_filename, 205 *out_filename; 206 char *database; 207 Oid lobjOid; 208 PGconn *conn; 209 PGresult *res; 210 211 if (argc != 4) 212 { 213 fprintf(stderr, "Usage: %s database_name in_filename out_filename\n", 214 argv[0]); 215 exit(1); 216 } 217 218 database = argv[1]; 219 in_filename = argv[2]; 220 out_filename = argv[3]; 221 222 /* 223 * set up the connection 224 */ 225 conn = PQsetdb(NULL, NULL, NULL, NULL, database); 226 227 /* check to see that the backend connection was successfully made */ 228 if (PQstatus(conn) != CONNECTION_OK) 229 { 230 fprintf(stderr, "Connection to database failed: %s", 231 PQerrorMessage(conn)); 232 exit_nicely(conn); 233 } 234 235 /* Set always-secure search path, so malicous users can't take control. */ 236 res = PQexec(conn, 237 "SELECT pg_catalog.set_config('search_path', '', false)"); 238 if (PQresultStatus(res) != PGRES_TUPLES_OK) 239 { 240 fprintf(stderr, "SET failed: %s", PQerrorMessage(conn)); 241 PQclear(res); 242 exit_nicely(conn); 243 } 244 PQclear(res); 245 246 res = PQexec(conn, "begin"); 247 PQclear(res); 248 printf("importing file \"%s\" ...\n", in_filename); 249 /* lobjOid = importFile(conn, in_filename); */ 250 lobjOid = lo_import(conn, in_filename); 251 if (lobjOid == 0) 252 fprintf(stderr, "%s\n", PQerrorMessage(conn)); 253 else 254 { 255 printf("\tas large object %u.\n", lobjOid); 256 257 printf("picking out bytes 1000-2000 of the large object\n"); 258 pickout(conn, lobjOid, 1000, 1000); 259 260 printf("overwriting bytes 1000-2000 of the large object with X's\n"); 261 overwrite(conn, lobjOid, 1000, 1000); 262 263 printf("exporting large object to file \"%s\" ...\n", out_filename); 264 /* exportFile(conn, lobjOid, out_filename); */ 265 if (lo_export(conn, lobjOid, out_filename) < 0) 266 fprintf(stderr, "%s\n", PQerrorMessage(conn)); 267 } 268 269 res = PQexec(conn, "end"); 270 PQclear(res); 271 PQfinish(conn); 272 return 0; 273 } 274