77 *
88 *
99 * IDENTIFICATION
10- * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.3 1996/11/08 06:02:28 momjian Exp $
10+ * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.4 1996/11/11 12:16:56 scrappy Exp $
1111 *
1212 *-------------------------------------------------------------------------
1313 */
1818#include <sys/types.h>
1919#include "postgres.h"
2020#include "libpq-fe.h"
21- #include "fmgr.h"
2221#include "libpq/libpq-fs.h"
2322
2423#ifndef MAXPATHLEN
2726
2827#define LO_BUFSIZE 1024
2928
29+ static int lo_initialize (PGconn * conn );
30+
3031/*
3132 * lo_open
3233 * opens an existing large object
@@ -49,8 +50,14 @@ lo_open(PGconn* conn, Oid lobjId, int mode)
4950argv [1 ].isint = 1 ;
5051argv [1 ].len = 4 ;
5152argv [1 ].u .integer = mode ;
53+
54+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
55+ if (lo_initialize (conn )< 0 ) {
56+ return -1 ;
57+ }
58+ }
5259
53- res = PQfn (conn ,F_LO_OPEN ,& fd ,& result_len ,1 ,argv ,2 );
60+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_open ,& fd ,& result_len ,1 ,argv ,2 );
5461if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
5562PQclear (res );
5663
@@ -78,10 +85,17 @@ lo_close(PGconn *conn, int fd)
7885int retval ;
7986int result_len ;
8087
88+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
89+ if (lo_initialize (conn )< 0 ) {
90+ return -1 ;
91+ }
92+ }
93+
8194argv [0 ].isint = 1 ;
8295argv [0 ].len = 4 ;
8396argv [0 ].u .integer = fd ;
84- res = PQfn (conn ,F_LO_CLOSE ,& retval ,& result_len ,1 ,argv ,1 );
97+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_close ,
98+ & retval ,& result_len ,1 ,argv ,1 );
8599if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
86100PQclear (res );
87101return retval ;
@@ -104,6 +118,12 @@ lo_read(PGconn *conn, int fd, char *buf, int len)
104118PGresult * res ;
105119int result_len ;
106120
121+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
122+ if (lo_initialize (conn )< 0 ) {
123+ return -1 ;
124+ }
125+ }
126+
107127argv [0 ].isint = 1 ;
108128argv [0 ].len = 4 ;
109129argv [0 ].u .integer = fd ;
@@ -112,7 +132,8 @@ lo_read(PGconn *conn, int fd, char *buf, int len)
112132argv [1 ].len = 4 ;
113133argv [1 ].u .integer = len ;
114134
115- res = PQfn (conn ,F_LOREAD ,(int * )buf ,& result_len ,0 ,argv ,2 );
135+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_read ,
136+ (int * )buf ,& result_len ,0 ,argv ,2 );
116137if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
117138PQclear (res );
118139return result_len ;
@@ -133,6 +154,12 @@ lo_write(PGconn *conn, int fd, char *buf, int len)
133154int result_len ;
134155int retval ;
135156
157+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
158+ if (lo_initialize (conn )< 0 ) {
159+ return -1 ;
160+ }
161+ }
162+
136163if (len <=0 )
137164return 0 ;
138165
@@ -144,7 +171,8 @@ lo_write(PGconn *conn, int fd, char *buf, int len)
144171argv [1 ].len = len ;
145172argv [1 ].u .ptr = (int * )buf ;
146173
147- res = PQfn (conn ,F_LOWRITE ,& retval ,& result_len ,1 ,argv ,2 );
174+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_write ,
175+ & retval ,& result_len ,1 ,argv ,2 );
148176if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
149177PQclear (res );
150178return retval ;
@@ -167,6 +195,12 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
167195int retval ;
168196int result_len ;
169197
198+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
199+ if (lo_initialize (conn )< 0 ) {
200+ return -1 ;
201+ }
202+ }
203+
170204argv [0 ].isint = 1 ;
171205argv [0 ].len = 4 ;
172206argv [0 ].u .integer = fd ;
@@ -179,7 +213,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence)
179213argv [2 ].len = 4 ;
180214argv [2 ].u .integer = whence ;
181215
182- res = PQfn (conn ,F_LO_LSEEK ,& retval ,& result_len ,1 ,argv ,3 );
216+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_lseek ,
217+ & retval ,& result_len ,1 ,argv ,3 );
183218if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
184219PQclear (res );
185220return retval ;
@@ -204,10 +239,17 @@ lo_creat(PGconn *conn, int mode)
204239int retval ;
205240int result_len ;
206241
242+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
243+ if (lo_initialize (conn )< 0 ) {
244+ return -1 ;
245+ }
246+ }
247+
207248argv [0 ].isint = 1 ;
208249argv [0 ].len = 4 ;
209250argv [0 ].u .integer = mode ;
210- res = PQfn (conn ,F_LO_CREAT ,& retval ,& result_len ,1 ,argv ,1 );
251+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_creat ,
252+ & retval ,& result_len ,1 ,argv ,1 );
211253if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
212254PQclear (res );
213255return (Oid )retval ;
@@ -230,11 +272,18 @@ lo_tell(PGconn *conn, int fd)
230272PGresult * res ;
231273int result_len ;
232274
275+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
276+ if (lo_initialize (conn )< 0 ) {
277+ return -1 ;
278+ }
279+ }
280+
233281argv [0 ].isint = 1 ;
234282argv [0 ].len = 4 ;
235283argv [0 ].u .integer = fd ;
236284
237- res = PQfn (conn ,F_LO_TELL ,& retval ,& result_len ,1 ,argv ,1 );
285+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_tell ,
286+ & retval ,& result_len ,1 ,argv ,1 );
238287if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
239288PQclear (res );
240289return retval ;
@@ -256,11 +305,18 @@ lo_unlink(PGconn *conn, Oid lobjId)
256305int result_len ;
257306int retval ;
258307
308+ if (conn -> lobjfuncs == (PGlobjfuncs * )NULL ) {
309+ if (lo_initialize (conn )< 0 ) {
310+ return -1 ;
311+ }
312+ }
313+
259314argv [0 ].isint = 1 ;
260315argv [0 ].len = 4 ;
261316argv [0 ].u .integer = lobjId ;
262317
263- res = PQfn (conn ,F_LO_UNLINK ,& retval ,& result_len ,1 ,argv ,1 );
318+ res = PQfn (conn ,conn -> lobjfuncs -> fn_lo_unlink ,
319+ & retval ,& result_len ,1 ,argv ,1 );
264320if (PQresultStatus (res )== PGRES_COMMAND_OK ) {
265321PQclear (res );
266322return retval ;
@@ -380,3 +436,157 @@ lo_export(PGconn *conn, Oid lobjId, char *filename)
380436
381437return 1 ;
382438}
439+
440+
441+ /* ----------------
442+ * lo_initialize
443+ *
444+ * Initialize the large object interface for an existing connection.
445+ * We ask the backend about the functions OID's in pg_proc for all
446+ * functions that are required for large object operations.
447+ * ----------------
448+ */
449+ static int lo_initialize (PGconn * conn )
450+ {
451+ PGresult * res ;
452+ PGlobjfuncs * lobjfuncs ;
453+ int n ;
454+ char * fname ;
455+ Oid foid ;
456+
457+ /* ----------------
458+ * Allocate the structure to hold the functions OID's
459+ * ----------------
460+ */
461+ lobjfuncs = (PGlobjfuncs * )malloc (sizeof (PGlobjfuncs ));
462+ if (lobjfuncs == (PGlobjfuncs * )NULL ) {
463+ strcpy (conn -> errorMessage ,
464+ "FATAL: malloc() failed in lo_initialize()\n" );
465+ return -1 ;
466+ }
467+ memset ((char * )lobjfuncs ,0 ,sizeof (PGlobjfuncs ));
468+
469+ /* ----------------
470+ * Execute the query to get all the functions at once
471+ * ----------------
472+ */
473+ res = PQexec (conn ,"select proname, oid from pg_proc\
474+ where proname = 'lo_open'\
475+ or proname = 'lo_close'\
476+ or proname = 'lo_creat'\
477+ or proname = 'lo_unlink'\
478+ or proname = 'lo_lseek'\
479+ or proname = 'lo_tell'\
480+ or proname = 'LOread'\
481+ or proname = 'LOwrite'" );
482+ if (res == (PGresult * )NULL ) {
483+ free (lobjfuncs );
484+ return -1 ;
485+ }
486+
487+ if (res -> resultStatus != PGRES_TUPLES_OK ) {
488+ free (lobjfuncs );
489+ PQclear (res );
490+ strcpy (conn -> errorMessage ,
491+ "ERROR: SELECT didn't return data in lo_initialize()\n" );
492+ return -1 ;
493+ }
494+
495+ /* ----------------
496+ * Examine the result and put the OID's into the struct
497+ * ----------------
498+ */
499+ for (n = 0 ;n < PQntuples (res );n ++ ) {
500+ fname = PQgetvalue (res ,n ,0 );
501+ foid = (Oid )atoi (PQgetvalue (res ,n ,1 ));
502+ if (!strcmp (fname ,"lo_open" )) {
503+ lobjfuncs -> fn_lo_open = foid ;
504+ }else
505+ if (!strcmp (fname ,"lo_close" )) {
506+ lobjfuncs -> fn_lo_close = foid ;
507+ }else
508+ if (!strcmp (fname ,"lo_creat" )) {
509+ lobjfuncs -> fn_lo_creat = foid ;
510+ }else
511+ if (!strcmp (fname ,"lo_unlink" )) {
512+ lobjfuncs -> fn_lo_unlink = foid ;
513+ }else
514+ if (!strcmp (fname ,"lo_lseek" )) {
515+ lobjfuncs -> fn_lo_lseek = foid ;
516+ }else
517+ if (!strcmp (fname ,"lo_tell" )) {
518+ lobjfuncs -> fn_lo_tell = foid ;
519+ }else
520+ if (!strcmp (fname ,"LOread" )) {
521+ lobjfuncs -> fn_lo_read = foid ;
522+ }else
523+ if (!strcmp (fname ,"LOwrite" )) {
524+ lobjfuncs -> fn_lo_write = foid ;
525+ }
526+ }
527+
528+ PQclear (res );
529+
530+ /* ----------------
531+ * Finally check that we really got all large object
532+ * interface functions.
533+ * ----------------
534+ */
535+ if (lobjfuncs -> fn_lo_open == 0 ) {
536+ strcpy (conn -> errorMessage ,
537+ "ERROR: Cannot determine OID for function lo_open\n" );
538+ free (lobjfuncs );
539+ return -1 ;
540+ }
541+ if (lobjfuncs -> fn_lo_close == 0 ) {
542+ strcpy (conn -> errorMessage ,
543+ "ERROR: Cannot determine OID for function lo_close\n" );
544+ free (lobjfuncs );
545+ return -1 ;
546+ }
547+ if (lobjfuncs -> fn_lo_creat == 0 ) {
548+ strcpy (conn -> errorMessage ,
549+ "ERROR: Cannot determine OID for function lo_creat\n" );
550+ free (lobjfuncs );
551+ return -1 ;
552+ }
553+ if (lobjfuncs -> fn_lo_unlink == 0 ) {
554+ strcpy (conn -> errorMessage ,
555+ "ERROR: Cannot determine OID for function lo_unlink\n" );
556+ free (lobjfuncs );
557+ return -1 ;
558+ }
559+ if (lobjfuncs -> fn_lo_lseek == 0 ) {
560+ strcpy (conn -> errorMessage ,
561+ "ERROR: Cannot determine OID for function lo_lseek\n" );
562+ free (lobjfuncs );
563+ return -1 ;
564+ }
565+ if (lobjfuncs -> fn_lo_tell == 0 ) {
566+ strcpy (conn -> errorMessage ,
567+ "ERROR: Cannot determine OID for function lo_tell\n" );
568+ free (lobjfuncs );
569+ return -1 ;
570+ }
571+ if (lobjfuncs -> fn_lo_read == 0 ) {
572+ strcpy (conn -> errorMessage ,
573+ "ERROR: Cannot determine OID for function LOread\n" );
574+ free (lobjfuncs );
575+ return -1 ;
576+ }
577+ if (lobjfuncs -> fn_lo_write == 0 ) {
578+ strcpy (conn -> errorMessage ,
579+ "ERROR: Cannot determine OID for function LOwrite\n" );
580+ free (lobjfuncs );
581+ return -1 ;
582+ }
583+
584+ /* ----------------
585+ * Put the structure into the connection control
586+ * ----------------
587+ */
588+ conn -> lobjfuncs = lobjfuncs ;
589+ return 0 ;
590+ }
591+
592+