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