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