]> granicus.if.org Git - postgresql/blob - src/interfaces/libpq/fe-lobj.c
Additional spelling corrections
[postgresql] / src / interfaces / libpq / fe-lobj.c
1 /*-------------------------------------------------------------------------
2  *
3  * fe-lobj.c
4  *        Front-end large object interface
5  *
6  * Portions Copyright (c) 1996-2013, 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
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
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
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
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
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                            (int *) 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
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
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
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                            (int *) &retval, &result_len, 0, argv, 3);
445         if (PQresultStatus(res) == PGRES_COMMAND_OK)
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
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
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
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
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                            (int *) &retval, &result_len, 0, argv, 1);
611         if (PQresultStatus(res) == PGRES_COMMAND_OK)
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
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
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
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
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
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
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
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
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 }