OSDN Git Service

Change error messages to oids come out as %u and not %d. Change has no
[pg-rex/syncrep.git] / src / interfaces / libpq / fe-lobj.c
1 /*-------------------------------------------------------------------------
2  *
3  * fe-lobj.c
4  *        Front-end large object interface
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.20 1999/05/10 00:46:26 momjian Exp $
11  *
12  *-------------------------------------------------------------------------
13  */
14
15 #include "libpq-fe.h"
16 #include "libpq-int.h"
17 #include "postgres.h"
18
19 #ifdef WIN32
20 #include "win32.h"
21 #include <io.h>
22 #else
23 #if !defined(NO_UNISTD_H)
24 #include <unistd.h>
25 #endif
26 #endif
27 #include <string.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30
31 #include "libpq/libpq-fs.h"             /* must come after sys/stat.h */
32
33
34 #define LO_BUFSIZE                1024
35
36 static int      lo_initialize(PGconn *conn);
37
38 /*
39  * lo_open
40  *        opens an existing large object
41  *
42  * returns the file descriptor for use in later lo_* calls
43  * return -1 upon failure.
44  */
45 int
46 lo_open(PGconn *conn, Oid lobjId, int mode)
47 {
48         int                     fd;
49         int                     result_len;
50         PQArgBlock      argv[2];
51         PGresult   *res;
52
53         argv[0].isint = 1;
54         argv[0].len = 4;
55         argv[0].u.integer = lobjId;
56
57         argv[1].isint = 1;
58         argv[1].len = 4;
59         argv[1].u.integer = mode;
60
61         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
62         {
63                 if (lo_initialize(conn) < 0)
64                         return -1;
65         }
66
67         res = PQfn(conn, conn->lobjfuncs->fn_lo_open, &fd, &result_len, 1, argv, 2);
68         if (PQresultStatus(res) == PGRES_COMMAND_OK)
69         {
70                 PQclear(res);
71
72                 /* have to do this to reset offset in shared fd cache */
73                 /* but only if fd is valid */
74                 if (fd >= 0 && lo_lseek(conn, fd, 0L, SEEK_SET) < 0)
75                         return -1;
76                 return fd;
77         }
78         else
79         {
80                 PQclear(res);
81                 return -1;
82         }
83 }
84
85 /*
86  * lo_close
87  *        closes an existing large object
88  *
89  * returns 0 upon success
90  * returns -1 upon failure.
91  */
92 int
93 lo_close(PGconn *conn, int fd)
94 {
95         PQArgBlock      argv[1];
96         PGresult   *res;
97         int                     retval;
98         int                     result_len;
99
100         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
101         {
102                 if (lo_initialize(conn) < 0)
103                         return -1;
104         }
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_read
125  *        read len bytes of the large object into buf
126  *
127  * returns the length of bytes read.
128  * the CALLER must have allocated enough space to hold the result returned
129  */
130
131 int
132 lo_read(PGconn *conn, int fd, char *buf, int len)
133 {
134         PQArgBlock      argv[2];
135         PGresult   *res;
136         int                     result_len;
137
138         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
139         {
140                 if (lo_initialize(conn) < 0)
141                         return -1;
142         }
143
144         argv[0].isint = 1;
145         argv[0].len = 4;
146         argv[0].u.integer = fd;
147
148         argv[1].isint = 1;
149         argv[1].len = 4;
150         argv[1].u.integer = len;
151
152         res = PQfn(conn, conn->lobjfuncs->fn_lo_read,
153                            (int *) buf, &result_len, 0, argv, 2);
154         if (PQresultStatus(res) == PGRES_COMMAND_OK)
155         {
156                 PQclear(res);
157                 return result_len;
158         }
159         else
160         {
161                 PQclear(res);
162                 return -1;
163         }
164 }
165
166 /*
167  * lo_write
168  *        write len bytes of buf into the large object fd
169  *
170  */
171 int
172 lo_write(PGconn *conn, int fd, char *buf, int len)
173 {
174         PQArgBlock      argv[2];
175         PGresult   *res;
176         int                     result_len;
177         int                     retval;
178
179         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
180         {
181                 if (lo_initialize(conn) < 0)
182                         return -1;
183         }
184
185         if (len <= 0)
186                 return 0;
187
188         argv[0].isint = 1;
189         argv[0].len = 4;
190         argv[0].u.integer = fd;
191
192         argv[1].isint = 0;
193         argv[1].len = len;
194         argv[1].u.ptr = (int *) buf;
195
196         res = PQfn(conn, conn->lobjfuncs->fn_lo_write,
197                            &retval, &result_len, 1, argv, 2);
198         if (PQresultStatus(res) == PGRES_COMMAND_OK)
199         {
200                 PQclear(res);
201                 return retval;
202         }
203         else
204         {
205                 PQclear(res);
206                 return -1;
207         }
208 }
209
210 /*
211  * lo_lseek
212  *        change the current read or write location on a large object
213  * currently, only L_SET is a legal value for whence
214  *
215  */
216
217 int
218 lo_lseek(PGconn *conn, int fd, int offset, int whence)
219 {
220         PQArgBlock      argv[3];
221         PGresult   *res;
222         int                     retval;
223         int                     result_len;
224
225         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
226         {
227                 if (lo_initialize(conn) < 0)
228                         return -1;
229         }
230
231         argv[0].isint = 1;
232         argv[0].len = 4;
233         argv[0].u.integer = fd;
234
235         argv[1].isint = 1;
236         argv[1].len = 4;
237         argv[1].u.integer = offset;
238
239         argv[2].isint = 1;
240         argv[2].len = 4;
241         argv[2].u.integer = whence;
242
243         res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek,
244                            &retval, &result_len, 1, argv, 3);
245         if (PQresultStatus(res) == PGRES_COMMAND_OK)
246         {
247                 PQclear(res);
248                 return retval;
249         }
250         else
251         {
252                 PQclear(res);
253                 return -1;
254         }
255 }
256
257 /*
258  * lo_creat
259  *        create a new large object
260  * the mode is a bitmask describing different attributes of the new object
261  *
262  * returns the oid of the large object created or
263  * InvalidOid upon failure
264  */
265
266 Oid
267 lo_creat(PGconn *conn, int mode)
268 {
269         PQArgBlock      argv[1];
270         PGresult   *res;
271         int                     retval;
272         int                     result_len;
273
274         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
275         {
276                 if (lo_initialize(conn) < 0)
277                         return -1;
278         }
279
280         argv[0].isint = 1;
281         argv[0].len = 4;
282         argv[0].u.integer = mode;
283         res = PQfn(conn, conn->lobjfuncs->fn_lo_creat,
284                            &retval, &result_len, 1, argv, 1);
285         if (PQresultStatus(res) == PGRES_COMMAND_OK)
286         {
287                 PQclear(res);
288                 return (Oid) retval;
289         }
290         else
291         {
292                 PQclear(res);
293                 return InvalidOid;
294         }
295 }
296
297
298 /*
299  * lo_tell
300  *        returns the current seek location of the large object
301  *
302  */
303
304 int
305 lo_tell(PGconn *conn, int fd)
306 {
307         int                     retval;
308         PQArgBlock      argv[1];
309         PGresult   *res;
310         int                     result_len;
311
312         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
313         {
314                 if (lo_initialize(conn) < 0)
315                         return -1;
316         }
317
318         argv[0].isint = 1;
319         argv[0].len = 4;
320         argv[0].u.integer = fd;
321
322         res = PQfn(conn, conn->lobjfuncs->fn_lo_tell,
323                            &retval, &result_len, 1, argv, 1);
324         if (PQresultStatus(res) == PGRES_COMMAND_OK)
325         {
326                 PQclear(res);
327                 return retval;
328         }
329         else
330         {
331                 PQclear(res);
332                 return -1;
333         }
334 }
335
336 /*
337  * lo_unlink
338  *        delete a file
339  *
340  */
341
342 int
343 lo_unlink(PGconn *conn, Oid lobjId)
344 {
345         PQArgBlock      argv[1];
346         PGresult   *res;
347         int                     result_len;
348         int                     retval;
349
350         if (conn->lobjfuncs == (PGlobjfuncs *) NULL)
351         {
352                 if (lo_initialize(conn) < 0)
353                         return -1;
354         }
355
356         argv[0].isint = 1;
357         argv[0].len = 4;
358         argv[0].u.integer = lobjId;
359
360         res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink,
361                            &retval, &result_len, 1, argv, 1);
362         if (PQresultStatus(res) == PGRES_COMMAND_OK)
363         {
364                 PQclear(res);
365                 return retval;
366         }
367         else
368         {
369                 PQclear(res);
370                 return -1;
371         }
372 }
373
374 /*
375  * lo_import -
376  *        imports a file as an (inversion) large object.
377  *              returns the oid of that object upon success,
378  * returns InvalidOid upon failure
379  *
380  */
381
382 Oid
383 lo_import(PGconn *conn, char *filename)
384 {
385         int                     fd;
386         int                     nbytes,
387                                 tmp;
388         char            buf[LO_BUFSIZE];
389         Oid                     lobjOid;
390         int                     lobj;
391
392         /*
393          * open the file to be read in
394          */
395 #ifndef __CYGWIN32__
396         fd = open(filename, O_RDONLY, 0666);
397 #else
398         fd = open(filename, O_RDONLY | O_BINARY, 0666);
399 #endif
400         if (fd < 0)
401         {                                                       /* error */
402                 sprintf(conn->errorMessage,
403                                 "lo_import: can't open unix file\"%s\"\n", filename);
404                 return InvalidOid;
405         }
406
407         /*
408          * create an inversion "object"
409          */
410         lobjOid = lo_creat(conn, INV_READ | INV_WRITE);
411         if (lobjOid == InvalidOid)
412         {
413                 sprintf(conn->errorMessage,
414                           "lo_import: can't create inv object for \"%s\"", filename);
415                 return InvalidOid;
416         }
417
418         lobj = lo_open(conn, lobjOid, INV_WRITE);
419         if (lobj == -1)
420         {
421                 sprintf(conn->errorMessage,
422                                 "lo_import: could not open inv object oid %u", lobjOid);
423                 return InvalidOid;
424         }
425
426         /*
427          * read in from the Unix file and write to the inversion file
428          */
429         while ((nbytes = read(fd, buf, LO_BUFSIZE)) > 0)
430         {
431                 tmp = lo_write(conn, lobj, buf, nbytes);
432                 if (tmp < nbytes)
433                 {
434                         sprintf(conn->errorMessage,
435                                         "lo_import: error while reading \"%s\"", filename);
436                         return InvalidOid;
437                 }
438         }
439
440         (void) close(fd);
441         (void) lo_close(conn, lobj);
442
443         return lobjOid;
444 }
445
446 /*
447  * lo_export -
448  *        exports an (inversion) large object.
449  * returns -1 upon failure, 1 otherwise
450  */
451 int
452 lo_export(PGconn *conn, Oid lobjId, char *filename)
453 {
454         int                     fd;
455         int                     nbytes,
456                                 tmp;
457         char            buf[LO_BUFSIZE];
458         int                     lobj;
459
460         /*
461          * create an inversion "object"
462          */
463         lobj = lo_open(conn, lobjId, INV_READ);
464         if (lobj == -1)
465         {
466                 sprintf(conn->errorMessage,
467                                 "lo_export: can't open inv object %u", lobjId);
468                 return -1;
469         }
470
471         /*
472          * open the file to be written to
473          */
474 #ifndef __CYGWIN32__
475         fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0666);
476 #else
477         fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, 0666);
478 #endif
479         if (fd < 0)
480         {                                                       /* error */
481                 sprintf(conn->errorMessage,
482                                 "lo_export: can't open unix file\"%s\"", filename);
483                 return 0;
484         }
485
486         /*
487          * read in from the Unix file and write to the inversion file
488          */
489         while ((nbytes = lo_read(conn, lobj, buf, LO_BUFSIZE)) > 0)
490         {
491                 tmp = write(fd, buf, nbytes);
492                 if (tmp < nbytes)
493                 {
494                         sprintf(conn->errorMessage,
495                                         "lo_export: error while writing \"%s\"",
496                                         filename);
497                         return -1;
498                 }
499         }
500
501         (void) lo_close(conn, lobj);
502         (void) close(fd);
503
504         return 1;
505 }
506
507
508 /* ----------------
509  * lo_initialize
510  *
511  * Initialize the large object interface for an existing connection.
512  * We ask the backend about the functions OID's in pg_proc for all
513  * functions that are required for large object operations.
514  * ----------------
515  */
516 static int
517 lo_initialize(PGconn *conn)
518 {
519         PGresult   *res;
520         PGlobjfuncs *lobjfuncs;
521         int                     n;
522         char       *fname;
523         Oid                     foid;
524
525         /* ----------------
526          * Allocate the structure to hold the functions OID's
527          * ----------------
528          */
529         lobjfuncs = (PGlobjfuncs *) malloc(sizeof(PGlobjfuncs));
530         if (lobjfuncs == (PGlobjfuncs *) NULL)
531         {
532                 strcpy(conn->errorMessage,
533                            "FATAL: malloc() failed in lo_initialize()\n");
534                 return -1;
535         }
536         MemSet((char *) lobjfuncs, 0, sizeof(PGlobjfuncs));
537
538         /* ----------------
539          * Execute the query to get all the functions at once
540          * ----------------
541          */
542         res = PQexec(conn, "select proname, oid from pg_proc    \
543                 where proname = 'lo_open'       \
544                    or proname = 'lo_close'      \
545                    or proname = 'lo_creat'      \
546                    or proname = 'lo_unlink'     \
547                    or proname = 'lo_lseek'      \
548                    or proname = 'lo_tell'       \
549                    or proname = 'loread'        \
550                    or proname = 'lowrite'");
551         if (res == (PGresult *) NULL)
552         {
553                 free(lobjfuncs);
554                 return -1;
555         }
556
557         if (res->resultStatus != PGRES_TUPLES_OK)
558         {
559                 free(lobjfuncs);
560                 PQclear(res);
561                 strcpy(conn->errorMessage,
562                            "ERROR: SELECT didn't return data in lo_initialize()\n");
563                 return -1;
564         }
565
566         /* ----------------
567          * Examine the result and put the OID's into the struct
568          * ----------------
569          */
570         for (n = 0; n < PQntuples(res); n++)
571         {
572                 fname = PQgetvalue(res, n, 0);
573                 foid = (Oid) atoi(PQgetvalue(res, n, 1));
574                 if (!strcmp(fname, "lo_open"))
575                         lobjfuncs->fn_lo_open = foid;
576                 else if (!strcmp(fname, "lo_close"))
577                         lobjfuncs->fn_lo_close = foid;
578                 else if (!strcmp(fname, "lo_creat"))
579                         lobjfuncs->fn_lo_creat = foid;
580                 else if (!strcmp(fname, "lo_unlink"))
581                         lobjfuncs->fn_lo_unlink = foid;
582                 else if (!strcmp(fname, "lo_lseek"))
583                         lobjfuncs->fn_lo_lseek = foid;
584                 else if (!strcmp(fname, "lo_tell"))
585                         lobjfuncs->fn_lo_tell = foid;
586                 else if (!strcmp(fname, "loread"))
587                         lobjfuncs->fn_lo_read = foid;
588                 else if (!strcmp(fname, "lowrite"))
589                         lobjfuncs->fn_lo_write = foid;
590         }
591
592         PQclear(res);
593
594         /* ----------------
595          * Finally check that we really got all large object
596          * interface functions.
597          * ----------------
598          */
599         if (lobjfuncs->fn_lo_open == 0)
600         {
601                 strcpy(conn->errorMessage,
602                            "ERROR: Cannot determine OID for function lo_open\n");
603                 free(lobjfuncs);
604                 return -1;
605         }
606         if (lobjfuncs->fn_lo_close == 0)
607         {
608                 strcpy(conn->errorMessage,
609                            "ERROR: Cannot determine OID for function lo_close\n");
610                 free(lobjfuncs);
611                 return -1;
612         }
613         if (lobjfuncs->fn_lo_creat == 0)
614         {
615                 strcpy(conn->errorMessage,
616                            "ERROR: Cannot determine OID for function lo_creat\n");
617                 free(lobjfuncs);
618                 return -1;
619         }
620         if (lobjfuncs->fn_lo_unlink == 0)
621         {
622                 strcpy(conn->errorMessage,
623                            "ERROR: Cannot determine OID for function lo_unlink\n");
624                 free(lobjfuncs);
625                 return -1;
626         }
627         if (lobjfuncs->fn_lo_lseek == 0)
628         {
629                 strcpy(conn->errorMessage,
630                            "ERROR: Cannot determine OID for function lo_lseek\n");
631                 free(lobjfuncs);
632                 return -1;
633         }
634         if (lobjfuncs->fn_lo_tell == 0)
635         {
636                 strcpy(conn->errorMessage,
637                            "ERROR: Cannot determine OID for function lo_tell\n");
638                 free(lobjfuncs);
639                 return -1;
640         }
641         if (lobjfuncs->fn_lo_read == 0)
642         {
643                 strcpy(conn->errorMessage,
644                            "ERROR: Cannot determine OID for function loread\n");
645                 free(lobjfuncs);
646                 return -1;
647         }
648         if (lobjfuncs->fn_lo_write == 0)
649         {
650                 strcpy(conn->errorMessage,
651                            "ERROR: Cannot determine OID for function lowrite\n");
652                 free(lobjfuncs);
653                 return -1;
654         }
655
656         /* ----------------
657          * Put the structure into the connection control
658          * ----------------
659          */
660         conn->lobjfuncs = lobjfuncs;
661         return 0;
662 }