1 /*-------------------------------------------------------------------------
2 *
3 * fe-lobj.c
4 * Front-end large object interface
5 *
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/interfaces/libpq/fe-lobj.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16 #ifdef WIN32
17 /*
18 * As unlink/rename are #define'd in port.h (via postgres_fe.h), io.h
19 * must be included first on MS C. Might as well do it for all WIN32's
20 * here.
21 */
22 #include <io.h>
23 #endif
24
25 #include "postgres_fe.h"
26
27 #ifdef WIN32
28 #include "win32.h"
29 #else
30 #include <unistd.h>
31 #endif
32
33 #include <fcntl.h>
34 #include <limits.h>
35 #include <sys/stat.h>
36 #include <netinet/in.h> /* for ntohl/htonl */
37 #include <arpa/inet.h>
38
39 #include "libpq-fe.h"
40 #include "libpq-int.h"
41 #include "libpq/libpq-fs.h" /* must come after sys/stat.h */
42
43 #define LO_BUFSIZE 8192
44
45 static int lo_initialize(PGconn *conn);
46 static Oid lo_import_internal(PGconn *conn, const char *filename, Oid oid);
47 static pg_int64 lo_hton64(pg_int64 host64);
48 static pg_int64 lo_ntoh64(pg_int64 net64);
49
50 /*
51 * lo_open
52 * opens an existing large object
53 *
54 * returns the file descriptor for use in later lo_* calls
55 * return -1 upon failure.
56 */
57 int
lo_open(PGconn * conn,Oid lobjId,int mode)58 lo_open(PGconn *conn, Oid lobjId, int mode)
59 {
60 int fd;
61 int result_len;
62 PQArgBlock argv[2];
63 PGresult *res;
64
65 if (conn == NULL || conn->lobjfuncs == NULL)
66 {
67 if (lo_initialize(conn) < 0)
68 return -1;
69 }
70
71 argv[0].isint = 1;
72 argv[0].len = 4;
73 argv[0].u.integer = lobjId;
74
75 argv[1].isint = 1;
76 argv[1].len = 4;
77 argv[1].u.integer = mode;
78
79 res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
80 if (PQresultStatus(res) == PGRES_COMMAND_OK)
81 {
82 PQclear(res);
83 return fd;
84 }
85 else
86 {
87 PQclear(res);
88 return -1;
89 }
90 }
91
92 /*
93 * lo_close
94 * closes an existing large object
95 *
96 * returns 0 upon success
97 * returns -1 upon failure.
98 */
99 int
lo_close(PGconn * conn,int fd)100 lo_close(PGconn *conn, int fd)
101 {
102 PQArgBlock argv[1];
103 PGresult *res;
104 int retval;
105 int result_len;
106
107 if (conn == NULL || conn->lobjfuncs == NULL)
108 {
109 if (lo_initialize(conn) < 0)
110 return -1;
111 }
112
113 argv[0].isint = 1;
114 argv[0].len = 4;
115 argv[0].u.integer = fd;
116 res = PQfn(conn, conn->lobjfuncs->fn_lo_close,
117 &retval, &result_len, 1, argv, 1);
118 if (PQresultStatus(res) == PGRES_COMMAND_OK)
119 {
120 PQclear(res);
121 return retval;
122 }
123 else
124 {
125 PQclear(res);
126 return -1;
127 }
128 }
129
130 /*
131 * lo_truncate
132 * truncates an existing large object to the given size
133 *
134 * returns 0 upon success
135 * returns -1 upon failure
136 */
137 int
lo_truncate(PGconn * conn,int fd,size_t len)138 lo_truncate(PGconn *conn, int fd, size_t len)
139 {
140 PQArgBlock argv[2];
141 PGresult *res;
142 int retval;
143 int result_len;
144
145 if (conn == NULL || conn->lobjfuncs == NULL)
146 {
147 if (lo_initialize(conn) < 0)
148 return -1;
149 }
150
151 /* Must check this on-the-fly because it's not there pre-8.3 */
152 if (conn->lobjfuncs->fn_lo_truncate == 0)
153 {
154 printfPQExpBuffer(&conn->errorMessage,
155 libpq_gettext("cannot determine OID of function lo_truncate\n"));
156 return -1;
157 }
158
159 /*
160 * Long ago, somebody thought it'd be a good idea to declare this function
161 * as taking size_t ... but the underlying backend function only accepts a
162 * signed int32 length. So throw error if the given value overflows
163 * int32. (A possible alternative is to automatically redirect the call
164 * to lo_truncate64; but if the caller wanted to rely on that backend
165 * function being available, he could have called lo_truncate64 for
166 * himself.)
167 */
168 if (len > (size_t) INT_MAX)
169 {
170 printfPQExpBuffer(&conn->errorMessage,
171 libpq_gettext("argument of lo_truncate exceeds integer range\n"));
172 return -1;
173 }
174
175 argv[0].isint = 1;
176 argv[0].len = 4;
177 argv[0].u.integer = fd;
178
179 argv[1].isint = 1;
180 argv[1].len = 4;
181 argv[1].u.integer = (int) len;
182
183 res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate,
184 &retval, &result_len, 1, argv, 2);
185
186 if (PQresultStatus(res) == PGRES_COMMAND_OK)
187 {
188 PQclear(res);
189 return retval;
190 }
191 else
192 {
193 PQclear(res);
194 return -1;
195 }
196 }
197
198 /*
199 * lo_truncate64
200 * truncates an existing large object to the given size
201 *
202 * returns 0 upon success
203 * returns -1 upon failure
204 */
205 int
lo_truncate64(PGconn * conn,int fd,pg_int64 len)206 lo_truncate64(PGconn *conn, int fd, pg_int64 len)
207 {
208 PQArgBlock argv[2];
209 PGresult *res;
210 int retval;
211 int result_len;
212
213 if (conn == NULL || conn->lobjfuncs == NULL)
214 {
215 if (lo_initialize(conn) < 0)
216 return -1;
217 }
218
219 if (conn->lobjfuncs->fn_lo_truncate64 == 0)
220 {
221 printfPQExpBuffer(&conn->errorMessage,
222 libpq_gettext("cannot determine OID of function lo_truncate64\n"));
223 return -1;
224 }
225
226 argv[0].isint = 1;
227 argv[0].len = 4;
228 argv[0].u.integer = fd;
229
230 len = lo_hton64(len);
231 argv[1].isint = 0;
232 argv[1].len = 8;
233 argv[1].u.ptr = (int *) &len;
234
235 res = PQfn(conn, conn->lobjfuncs->fn_lo_truncate64,
236 &retval, &result_len, 1, argv, 2);
237
238 if (PQresultStatus(res) == PGRES_COMMAND_OK)
239 {
240 PQclear(res);
241 return retval;
242 }
243 else
244 {
245 PQclear(res);
246 return -1;
247 }
248 }
249
250 /*
251 * lo_read
252 * read len bytes of the large object into buf
253 *
254 * returns the number of bytes read, or -1 on failure.
255 * the CALLER must have allocated enough space to hold the result returned
256 */
257
258 int
lo_read(PGconn * conn,int fd,char * buf,size_t len)259 lo_read(PGconn *conn, int fd, char *buf, size_t len)
260 {
261 PQArgBlock argv[2];
262 PGresult *res;
263 int result_len;
264
265 if (conn == NULL || conn->lobjfuncs == NULL)
266 {
267 if (lo_initialize(conn) < 0)
268 return -1;
269 }
270
271 /*
272 * Long ago, somebody thought it'd be a good idea to declare this function
273 * as taking size_t ... but the underlying backend function only accepts a
274 * signed int32 length. So throw error if the given value overflows
275 * int32.
276 */
277 if (len > (size_t) INT_MAX)
278 {
279 printfPQExpBuffer(&conn->errorMessage,
280 libpq_gettext("argument of lo_read exceeds integer range\n"));
281 return -1;
282 }
283
284 argv[0].isint = 1;
285 argv[0].len = 4;
286 argv[0].u.integer = fd;
287
288 argv[1].isint = 1;
289 argv[1].len = 4;
290 argv[1].u.integer = (int) len;
291
292 res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
293 (void *) buf, &result_len, 0, argv, 2);
294 if (PQresultStatus(res) == PGRES_COMMAND_OK)
295 {
296 PQclear(res);
297 return result_len;
298 }
299 else
300 {
301 PQclear(res);
302 return -1;
303 }
304 }
305
306 /*
307 * lo_write
308 * write len bytes of buf into the large object fd
309 *
310 * returns the number of bytes written, or -1 on failure.
311 */
312 int
lo_write(PGconn * conn,int fd,const char * buf,size_t len)313 lo_write(PGconn *conn, int fd, const char *buf, size_t len)
314 {
315 PQArgBlock argv[2];
316 PGresult *res;
317 int result_len;
318 int retval;
319
320 if (conn == NULL || conn->lobjfuncs == NULL)
321 {
322 if (lo_initialize(conn) < 0)
323 return -1;
324 }
325
326 /*
327 * Long ago, somebody thought it'd be a good idea to declare this function
328 * as taking size_t ... but the underlying backend function only accepts a
329 * signed int32 length. So throw error if the given value overflows
330 * int32.
331 */
332 if (len > (size_t) INT_MAX)
333 {
334 printfPQExpBuffer(&conn->errorMessage,
335 libpq_gettext("argument of lo_write exceeds integer range\n"));
336 return -1;
337 }
338
339 argv[0].isint = 1;
340 argv[0].len = 4;
341 argv[0].u.integer = fd;
342
343 argv[1].isint = 0;
344 argv[1].len = (int) len;
345 argv[1].u.ptr = (int *) buf;
346
347 res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
348 &retval, &result_len, 1, argv, 2);
349 if (PQresultStatus(res) == PGRES_COMMAND_OK)
350 {
351 PQclear(res);
352 return retval;
353 }
354 else
355 {
356 PQclear(res);
357 return -1;
358 }
359 }
360
361 /*
362 * lo_lseek
363 * change the current read or write location on a large object
364 */
365 int
lo_lseek(PGconn * conn,int fd,int offset,int whence)366 lo_lseek(PGconn *conn, int fd, int offset, int whence)
367 {
368 PQArgBlock argv[3];
369 PGresult *res;
370 int retval;
371 int result_len;
372
373 if (conn == NULL || conn->lobjfuncs == NULL)
374 {
375 if (lo_initialize(conn) < 0)
376 return -1;
377 }
378
379 argv[0].isint = 1;
380 argv[0].len = 4;
381 argv[0].u.integer = fd;
382
383 argv[1].isint = 1;
384 argv[1].len = 4;
385 argv[1].u.integer = offset;
386
387 argv[2].isint = 1;
388 argv[2].len = 4;
389 argv[2].u.integer = whence;
390
391 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
392 &retval, &result_len, 1, argv, 3);
393 if (PQresultStatus(res) == PGRES_COMMAND_OK)
394 {
395 PQclear(res);
396 return retval;
397 }
398 else
399 {
400 PQclear(res);
401 return -1;
402 }
403 }
404
405 /*
406 * lo_lseek64
407 * change the current read or write location on a large object
408 */
409 pg_int64
lo_lseek64(PGconn * conn,int fd,pg_int64 offset,int whence)410 lo_lseek64(PGconn *conn, int fd, pg_int64 offset, int whence)
411 {
412 PQArgBlock argv[3];
413 PGresult *res;
414 pg_int64 retval;
415 int result_len;
416
417 if (conn == NULL || conn->lobjfuncs == NULL)
418 {
419 if (lo_initialize(conn) < 0)
420 return -1;
421 }
422
423 if (conn->lobjfuncs->fn_lo_lseek64 == 0)
424 {
425 printfPQExpBuffer(&conn->errorMessage,
426 libpq_gettext("cannot determine OID of function lo_lseek64\n"));
427 return -1;
428 }
429
430 argv[0].isint = 1;
431 argv[0].len = 4;
432 argv[0].u.integer = fd;
433
434 offset = lo_hton64(offset);
435 argv[1].isint = 0;
436 argv[1].len = 8;
437 argv[1].u.ptr = (int *) &offset;
438
439 argv[2].isint = 1;
440 argv[2].len = 4;
441 argv[2].u.integer = whence;
442
443 res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek64,
444 (void *) &retval, &result_len, 0, argv, 3);
445 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
446 {
447 PQclear(res);
448 return lo_ntoh64(retval);
449 }
450 else
451 {
452 PQclear(res);
453 return -1;
454 }
455 }
456
457 /*
458 * lo_creat
459 * create a new large object
460 * the mode is ignored (once upon a time it had a use)
461 *
462 * returns the oid of the large object created or
463 * InvalidOid upon failure
464 */
465 Oid
lo_creat(PGconn * conn,int mode)466 lo_creat(PGconn *conn, int mode)
467 {
468 PQArgBlock argv[1];
469 PGresult *res;
470 int retval;
471 int result_len;
472
473 if (conn == NULL || conn->lobjfuncs == NULL)
474 {
475 if (lo_initialize(conn) < 0)
476 return InvalidOid;
477 }
478
479 argv[0].isint = 1;
480 argv[0].len = 4;
481 argv[0].u.integer = mode;
482 res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
483 &retval, &result_len, 1, argv, 1);
484 if (PQresultStatus(res) == PGRES_COMMAND_OK)
485 {
486 PQclear(res);
487 return (Oid) retval;
488 }
489 else
490 {
491 PQclear(res);
492 return InvalidOid;
493 }
494 }
495
496 /*
497 * lo_create
498 * create a new large object
499 * if lobjId isn't InvalidOid, it specifies the OID to (attempt to) create
500 *
501 * returns the oid of the large object created or
502 * InvalidOid upon failure
503 */
504 Oid
lo_create(PGconn * conn,Oid lobjId)505 lo_create(PGconn *conn, Oid lobjId)
506 {
507 PQArgBlock argv[1];
508 PGresult *res;
509 int retval;
510 int result_len;
511
512 if (conn == NULL || conn->lobjfuncs == NULL)
513 {
514 if (lo_initialize(conn) < 0)
515 return InvalidOid;
516 }
517
518 /* Must check this on-the-fly because it's not there pre-8.1 */
519 if (conn->lobjfuncs->fn_lo_create == 0)
520 {
521 printfPQExpBuffer(&conn->errorMessage,
522 libpq_gettext("cannot determine OID of function lo_create\n"));
523 return InvalidOid;
524 }
525
526 argv[0].isint = 1;
527 argv[0].len = 4;
528 argv[0].u.integer = lobjId;
529 res = PQfn(conn, conn->lobjfuncs->fn_lo_create,
530 &retval, &result_len, 1, argv, 1);
531 if (PQresultStatus(res) == PGRES_COMMAND_OK)
532 {
533 PQclear(res);
534 return (Oid) retval;
535 }
536 else
537 {
538 PQclear(res);
539 return InvalidOid;
540 }
541 }
542
543
544 /*
545 * lo_tell
546 * returns the current seek location of the large object
547 */
548 int
lo_tell(PGconn * conn,int fd)549 lo_tell(PGconn *conn, int fd)
550 {
551 int retval;
552 PQArgBlock argv[1];
553 PGresult *res;
554 int result_len;
555
556 if (conn == NULL || conn->lobjfuncs == NULL)
557 {
558 if (lo_initialize(conn) < 0)
559 return -1;
560 }
561
562 argv[0].isint = 1;
563 argv[0].len = 4;
564 argv[0].u.integer = fd;
565
566 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
567 &retval, &result_len, 1, argv, 1);
568 if (PQresultStatus(res) == PGRES_COMMAND_OK)
569 {
570 PQclear(res);
571 return retval;
572 }
573 else
574 {
575 PQclear(res);
576 return -1;
577 }
578 }
579
580 /*
581 * lo_tell64
582 * returns the current seek location of the large object
583 */
584 pg_int64
lo_tell64(PGconn * conn,int fd)585 lo_tell64(PGconn *conn, int fd)
586 {
587 pg_int64 retval;
588 PQArgBlock argv[1];
589 PGresult *res;
590 int result_len;
591
592 if (conn == NULL || conn->lobjfuncs == NULL)
593 {
594 if (lo_initialize(conn) < 0)
595 return -1;
596 }
597
598 if (conn->lobjfuncs->fn_lo_tell64 == 0)
599 {
600 printfPQExpBuffer(&conn->errorMessage,
601 libpq_gettext("cannot determine OID of function lo_tell64\n"));
602 return -1;
603 }
604
605 argv[0].isint = 1;
606 argv[0].len = 4;
607 argv[0].u.integer = fd;
608
609 res = PQfn(conn, conn->lobjfuncs->fn_lo_tell64,
610 (void *) &retval, &result_len, 0, argv, 1);
611 if (PQresultStatus(res) == PGRES_COMMAND_OK && result_len == 8)
612 {
613 PQclear(res);
614 return lo_ntoh64(retval);
615 }
616 else
617 {
618 PQclear(res);
619 return -1;
620 }
621 }
622
623 /*
624 * lo_unlink
625 * delete a file
626 */
627
628 int
lo_unlink(PGconn * conn,Oid lobjId)629 lo_unlink(PGconn *conn, Oid lobjId)
630 {
631 PQArgBlock argv[1];
632 PGresult *res;
633 int result_len;
634 int retval;
635
636 if (conn == NULL || conn->lobjfuncs == NULL)
637 {
638 if (lo_initialize(conn) < 0)
639 return -1;
640 }
641
642 argv[0].isint = 1;
643 argv[0].len = 4;
644 argv[0].u.integer = lobjId;
645
646 res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
647 &retval, &result_len, 1, argv, 1);
648 if (PQresultStatus(res) == PGRES_COMMAND_OK)
649 {
650 PQclear(res);
651 return retval;
652 }
653 else
654 {
655 PQclear(res);
656 return -1;
657 }
658 }
659
660 /*
661 * lo_import -
662 * imports a file as an (inversion) large object.
663 *
664 * returns the oid of that object upon success,
665 * returns InvalidOid upon failure
666 */
667
668 Oid
lo_import(PGconn * conn,const char * filename)669 lo_import(PGconn *conn, const char *filename)
670 {
671 return lo_import_internal(conn, filename, InvalidOid);
672 }
673
674 /*
675 * lo_import_with_oid -
676 * imports a file as an (inversion) large object.
677 * large object id can be specified.
678 *
679 * returns the oid of that object upon success,
680 * returns InvalidOid upon failure
681 */
682
683 Oid
lo_import_with_oid(PGconn * conn,const char * filename,Oid lobjId)684 lo_import_with_oid(PGconn *conn, const char *filename, Oid lobjId)
685 {
686 return lo_import_internal(conn, filename, lobjId);
687 }
688
689 static Oid
lo_import_internal(PGconn * conn,const char * filename,Oid oid)690 lo_import_internal(PGconn *conn, const char *filename, Oid oid)
691 {
692 int fd;
693 int nbytes,
694 tmp;
695 char buf[LO_BUFSIZE];
696 Oid lobjOid;
697 int lobj;
698 char sebuf[256];
699
700 /*
701 * open the file to be read in
702 */
703 fd = open(filename, O_RDONLY | PG_BINARY, 0666);
704 if (fd < 0)
705 { /* error */
706 printfPQExpBuffer(&conn->errorMessage,
707 libpq_gettext("could not open file \"%s\": %s\n"),
708 filename, pqStrerror(errno, sebuf, sizeof(sebuf)));
709 return InvalidOid;
710 }
711
712 /*
713 * create an inversion object
714 */
715 if (oid == InvalidOid)
716 lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
717 else
718 lobjOid = lo_create(conn, oid);
719
720 if (lobjOid == InvalidOid)
721 {
722 /* we assume lo_create() already set a suitable error message */
723 (void) close(fd);
724 return InvalidOid;
725 }
726
727 lobj = lo_open(conn, lobjOid, INV_WRITE);
728 if (lobj == -1)
729 {
730 /* we assume lo_open() already set a suitable error message */
731 (void) close(fd);
732 return InvalidOid;
733 }
734
735 /*
736 * read in from the file and write to the large object
737 */
738 while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
739 {
740 tmp = lo_write(conn, lobj, buf, nbytes);
741 if (tmp != nbytes)
742 {
743 /*
744 * If lo_write() failed, we are now in an aborted transaction so
745 * there's no need for lo_close(); furthermore, if we tried it
746 * we'd overwrite the useful error result with a useless one. So
747 * just nail the doors shut and get out of town.
748 */
749 (void) close(fd);
750 return InvalidOid;
751 }
752 }
753
754 if (nbytes < 0)
755 {
756 /* We must do lo_close before setting the errorMessage */
757 int save_errno = errno;
758
759 (void) lo_close(conn, lobj);
760 (void) close(fd);
761 printfPQExpBuffer(&conn->errorMessage,
762 libpq_gettext("could not read from file \"%s\": %s\n"),
763 filename,
764 pqStrerror(save_errno, sebuf, sizeof(sebuf)));
765 return InvalidOid;
766 }
767
768 (void) close(fd);
769
770 if (lo_close(conn, lobj) != 0)
771 {
772 /* we assume lo_close() already set a suitable error message */
773 return InvalidOid;
774 }
775
776 return lobjOid;
777 }
778
779 /*
780 * lo_export -
781 * exports an (inversion) large object.
782 * returns -1 upon failure, 1 if OK
783 */
784 int
lo_export(PGconn * conn,Oid lobjId,const char * filename)785 lo_export(PGconn *conn, Oid lobjId, const char *filename)
786 {
787 int result = 1;
788 int fd;
789 int nbytes,
790 tmp;
791 char buf[LO_BUFSIZE];
792 int lobj;
793 char sebuf[256];
794
795 /*
796 * open the large object.
797 */
798 lobj = lo_open(conn, lobjId, INV_READ);
799 if (lobj == -1)
800 {
801 /* we assume lo_open() already set a suitable error message */
802 return -1;
803 }
804
805 /*
806 * create the file to be written to
807 */
808 fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
809 if (fd < 0)
810 {
811 /* We must do lo_close before setting the errorMessage */
812 int save_errno = errno;
813
814 (void) lo_close(conn, lobj);
815 printfPQExpBuffer(&conn->errorMessage,
816 libpq_gettext("could not open file \"%s\": %s\n"),
817 filename,
818 pqStrerror(save_errno, sebuf, sizeof(sebuf)));
819 return -1;
820 }
821
822 /*
823 * read in from the large object and write to the file
824 */
825 while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
826 {
827 tmp = write(fd, buf, nbytes);
828 if (tmp != nbytes)
829 {
830 /* We must do lo_close before setting the errorMessage */
831 int save_errno = errno;
832
833 (void) lo_close(conn, lobj);
834 (void) close(fd);
835 printfPQExpBuffer(&conn->errorMessage,
836 libpq_gettext("could not write to file \"%s\": %s\n"),
837 filename,
838 pqStrerror(save_errno, sebuf, sizeof(sebuf)));
839 return -1;
840 }
841 }
842
843 /*
844 * If lo_read() failed, we are now in an aborted transaction so there's no
845 * need for lo_close(); furthermore, if we tried it we'd overwrite the
846 * useful error result with a useless one. So skip lo_close() if we got a
847 * failure result.
848 */
849 if (nbytes < 0 ||
850 lo_close(conn, lobj) != 0)
851 {
852 /* assume lo_read() or lo_close() left a suitable error message */
853 result = -1;
854 }
855
856 /* if we already failed, don't overwrite that msg with a close error */
857 if (close(fd) && result >= 0)
858 {
859 printfPQExpBuffer(&conn->errorMessage,
860 libpq_gettext("could not write to file \"%s\": %s\n"),
861 filename, pqStrerror(errno, sebuf, sizeof(sebuf)));
862 result = -1;
863 }
864
865 return result;
866 }
867
868
869 /*
870 * lo_initialize
871 *
872 * Initialize the large object interface for an existing connection.
873 * We ask the backend about the functions OID's in pg_proc for all
874 * functions that are required for large object operations.
875 */
876 static int
lo_initialize(PGconn * conn)877 lo_initialize(PGconn *conn)
878 {
879 PGresult *res;
880 PGlobjfuncs *lobjfuncs;
881 int n;
882 const char *query;
883 const char *fname;
884 Oid foid;
885
886 if (!conn)
887 return -1;
888
889 /*
890 * Allocate the structure to hold the functions OID's
891 */
892 lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
893 if (lobjfuncs == NULL)
894 {
895 printfPQExpBuffer(&conn->errorMessage,
896 libpq_gettext("out of memory\n"));
897 return -1;
898 }
899 MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
900
901 /*
902 * Execute the query to get all the functions at once. In 7.3 and later
903 * we need to be schema-safe. lo_create only exists in 8.1 and up.
904 * lo_truncate only exists in 8.3 and up.
905 */
906 if (conn->sversion >= 70300)
907 query = "select proname, oid from pg_catalog.pg_proc "
908 "where proname in ("
909 "'lo_open', "
910 "'lo_close', "
911 "'lo_creat', "
912 "'lo_create', "
913 "'lo_unlink', "
914 "'lo_lseek', "
915 "'lo_lseek64', "
916 "'lo_tell', "
917 "'lo_tell64', "
918 "'lo_truncate', "
919 "'lo_truncate64', "
920 "'loread', "
921 "'lowrite') "
922 "and pronamespace = (select oid from pg_catalog.pg_namespace "
923 "where nspname = 'pg_catalog')";
924 else
925 query = "select proname, oid from pg_proc "
926 "where proname = 'lo_open' "
927 "or proname = 'lo_close' "
928 "or proname = 'lo_creat' "
929 "or proname = 'lo_unlink' "
930 "or proname = 'lo_lseek' "
931 "or proname = 'lo_tell' "
932 "or proname = 'loread' "
933 "or proname = 'lowrite'";
934
935 res = PQexec(conn, query);
936 if (res == NULL)
937 {
938 free(lobjfuncs);
939 return -1;
940 }
941
942 if (res->resultStatus != PGRES_TUPLES_OK)
943 {
944 free(lobjfuncs);
945 PQclear(res);
946 printfPQExpBuffer(&conn->errorMessage,
947 libpq_gettext("query to initialize large object functions did not return data\n"));
948 return -1;
949 }
950
951 /*
952 * Examine the result and put the OID's into the struct
953 */
954 for (n = 0; n < PQntuples(res); n++)
955 {
956 fname = PQgetvalue(res, n, 0);
957 foid = (Oid) atoi(PQgetvalue(res, n, 1));
958 if (strcmp(fname, "lo_open") == 0)
959 lobjfuncs->fn_lo_open = foid;
960 else if (strcmp(fname, "lo_close") == 0)
961 lobjfuncs->fn_lo_close = foid;
962 else if (strcmp(fname, "lo_creat") == 0)
963 lobjfuncs->fn_lo_creat = foid;
964 else if (strcmp(fname, "lo_create") == 0)
965 lobjfuncs->fn_lo_create = foid;
966 else if (strcmp(fname, "lo_unlink") == 0)
967 lobjfuncs->fn_lo_unlink = foid;
968 else if (strcmp(fname, "lo_lseek") == 0)
969 lobjfuncs->fn_lo_lseek = foid;
970 else if (strcmp(fname, "lo_lseek64") == 0)
971 lobjfuncs->fn_lo_lseek64 = foid;
972 else if (strcmp(fname, "lo_tell") == 0)
973 lobjfuncs->fn_lo_tell = foid;
974 else if (strcmp(fname, "lo_tell64") == 0)
975 lobjfuncs->fn_lo_tell64 = foid;
976 else if (strcmp(fname, "lo_truncate") == 0)
977 lobjfuncs->fn_lo_truncate = foid;
978 else if (strcmp(fname, "lo_truncate64") == 0)
979 lobjfuncs->fn_lo_truncate64 = foid;
980 else if (strcmp(fname, "loread") == 0)
981 lobjfuncs->fn_lo_read = foid;
982 else if (strcmp(fname, "lowrite") == 0)
983 lobjfuncs->fn_lo_write = foid;
984 }
985
986 PQclear(res);
987
988 /*
989 * Finally check that we got all required large object interface functions
990 * (ones that have been added later than the stone age are instead checked
991 * only if used)
992 */
993 if (lobjfuncs->fn_lo_open == 0)
994 {
995 printfPQExpBuffer(&conn->errorMessage,
996 libpq_gettext("cannot determine OID of function lo_open\n"));
997 free(lobjfuncs);
998 return -1;
999 }
1000 if (lobjfuncs->fn_lo_close == 0)
1001 {
1002 printfPQExpBuffer(&conn->errorMessage,
1003 libpq_gettext("cannot determine OID of function lo_close\n"));
1004 free(lobjfuncs);
1005 return -1;
1006 }
1007 if (lobjfuncs->fn_lo_creat == 0)
1008 {
1009 printfPQExpBuffer(&conn->errorMessage,
1010 libpq_gettext("cannot determine OID of function lo_creat\n"));
1011 free(lobjfuncs);
1012 return -1;
1013 }
1014 if (lobjfuncs->fn_lo_unlink == 0)
1015 {
1016 printfPQExpBuffer(&conn->errorMessage,
1017 libpq_gettext("cannot determine OID of function lo_unlink\n"));
1018 free(lobjfuncs);
1019 return -1;
1020 }
1021 if (lobjfuncs->fn_lo_lseek == 0)
1022 {
1023 printfPQExpBuffer(&conn->errorMessage,
1024 libpq_gettext("cannot determine OID of function lo_lseek\n"));
1025 free(lobjfuncs);
1026 return -1;
1027 }
1028 if (lobjfuncs->fn_lo_tell == 0)
1029 {
1030 printfPQExpBuffer(&conn->errorMessage,
1031 libpq_gettext("cannot determine OID of function lo_tell\n"));
1032 free(lobjfuncs);
1033 return -1;
1034 }
1035 if (lobjfuncs->fn_lo_read == 0)
1036 {
1037 printfPQExpBuffer(&conn->errorMessage,
1038 libpq_gettext("cannot determine OID of function loread\n"));
1039 free(lobjfuncs);
1040 return -1;
1041 }
1042 if (lobjfuncs->fn_lo_write == 0)
1043 {
1044 printfPQExpBuffer(&conn->errorMessage,
1045 libpq_gettext("cannot determine OID of function lowrite\n"));
1046 free(lobjfuncs);
1047 return -1;
1048 }
1049
1050 /*
1051 * Put the structure into the connection control
1052 */
1053 conn->lobjfuncs = lobjfuncs;
1054 return 0;
1055 }
1056
1057 /*
1058 * lo_hton64
1059 * converts a 64-bit integer from host byte order to network byte order
1060 */
1061 static pg_int64
lo_hton64(pg_int64 host64)1062 lo_hton64(pg_int64 host64)
1063 {
1064 union
1065 {
1066 pg_int64 i64;
1067 uint32 i32[2];
1068 } swap;
1069 uint32 t;
1070
1071 /* High order half first, since we're doing MSB-first */
1072 t = (uint32) (host64 >> 32);
1073 swap.i32[0] = htonl(t);
1074
1075 /* Now the low order half */
1076 t = (uint32) host64;
1077 swap.i32[1] = htonl(t);
1078
1079 return swap.i64;
1080 }
1081
1082 /*
1083 * lo_ntoh64
1084 * converts a 64-bit integer from network byte order to host byte order
1085 */
1086 static pg_int64
lo_ntoh64(pg_int64 net64)1087 lo_ntoh64(pg_int64 net64)
1088 {
1089 union
1090 {
1091 pg_int64 i64;
1092 uint32 i32[2];
1093 } swap;
1094 pg_int64 result;
1095
1096 swap.i64 = net64;
1097
1098 result = (uint32) ntohl(swap.i32[0]);
1099 result <<= 32;
1100 result |= (uint32) ntohl(swap.i32[1]);
1101
1102 return result;
1103 }
1104