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