From 41b8c2c849cfa5f10263c40fd09bc8448a593724 Mon Sep 17 00:00:00 2001 From: "Marc G. Fournier" Date: Mon, 11 Nov 1996 12:16:57 +0000 Subject: [PATCH] As proposed, following is the patch to libpq's large object interface that removes the requirement to include fmgr.h into fe-lobj.c. The large object interface now ask's the backend to tell the OID's of all the required functions in pg_proc. From: wieck@sapserv.debis.de (Jan Wieck) --- src/interfaces/libpq/fe-connect.c | 5 +- src/interfaces/libpq/fe-lobj.c | 230 ++++++++++++++++++++++++++++-- src/interfaces/libpq/libpq-fe.h | 14 +- 3 files changed, 237 insertions(+), 12 deletions(-) diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c index 8e733d5956..49cd005cb1 100644 --- a/src/interfaces/libpq/fe-connect.c +++ b/src/interfaces/libpq/fe-connect.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.17 1996/11/10 03:06:36 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.18 1996/11/11 12:16:54 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -192,6 +192,7 @@ PQconnectdb(const char *conninfo) conn->Pfdebug = NULL; conn->port = NULL; conn->notifyList = DLNewList(); + conn->lobjfuncs = NULL; conn->pghost = strdup(conninfo_getval("host")); conn->pgport = strdup(conninfo_getval("port")); @@ -299,6 +300,7 @@ PQsetdb(const char *pghost, const char* pgport, const char* pgoptions, const cha conn->Pfdebug = NULL; conn->port = NULL; conn->notifyList = DLNewList(); + conn->lobjfuncs = NULL; if (!pghost || pghost[0] == '\0') { if (!(tmp = getenv("PGHOST"))) { @@ -519,6 +521,7 @@ freePGconn(PGconn *conn) if (conn->dbName) free(conn->dbName); if (conn->pguser) free(conn->pguser); if (conn->notifyList) DLFreeList(conn->notifyList); + if (conn->lobjfuncs) free(conn->lobjfuncs); free(conn); } diff --git a/src/interfaces/libpq/fe-lobj.c b/src/interfaces/libpq/fe-lobj.c index b2c90331d2..551e89fec6 100644 --- a/src/interfaces/libpq/fe-lobj.c +++ b/src/interfaces/libpq/fe-lobj.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.3 1996/11/08 06:02:28 momjian Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-lobj.c,v 1.4 1996/11/11 12:16:56 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,6 @@ #include #include "postgres.h" #include "libpq-fe.h" -#include "fmgr.h" #include "libpq/libpq-fs.h" #ifndef MAXPATHLEN @@ -27,6 +26,8 @@ #define LO_BUFSIZE 1024 +static int lo_initialize(PGconn *conn); + /* * lo_open * opens an existing large object @@ -49,8 +50,14 @@ lo_open(PGconn* conn, Oid lobjId, int mode) argv[1].isint = 1; argv[1].len = 4; argv[1].u.integer = mode; + + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } - res = PQfn(conn, F_LO_OPEN,&fd,&result_len,1,argv,2); + res = PQfn(conn, conn->lobjfuncs->fn_lo_open,&fd,&result_len,1,argv,2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); @@ -78,10 +85,17 @@ lo_close(PGconn *conn, int fd) int retval; int result_len; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; - res = PQfn(conn, F_LO_CLOSE,&retval,&result_len,1,argv,1); + res = PQfn(conn, conn->lobjfuncs->fn_lo_close, + &retval,&result_len,1,argv,1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; @@ -104,6 +118,12 @@ lo_read(PGconn *conn, int fd, char *buf, int len) PGresult *res; int result_len; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; @@ -112,7 +132,8 @@ lo_read(PGconn *conn, int fd, char *buf, int len) argv[1].len = 4; argv[1].u.integer = len; - res = PQfn(conn, F_LOREAD,(int*)buf,&result_len,0,argv,2); + res = PQfn(conn, conn->lobjfuncs->fn_lo_read, + (int*)buf,&result_len,0,argv,2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return result_len; @@ -133,6 +154,12 @@ lo_write(PGconn *conn, int fd, char *buf, int len) int result_len; int retval; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + if (len <= 0) return 0; @@ -144,7 +171,8 @@ lo_write(PGconn *conn, int fd, char *buf, int len) argv[1].len = len; argv[1].u.ptr = (int*)buf; - res = PQfn(conn, F_LOWRITE,&retval,&result_len,1,argv,2); + res = PQfn(conn, conn->lobjfuncs->fn_lo_write, + &retval,&result_len,1,argv,2); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; @@ -167,6 +195,12 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) int retval; int result_len; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; @@ -179,7 +213,8 @@ lo_lseek(PGconn *conn, int fd, int offset, int whence) argv[2].len = 4; argv[2].u.integer = whence; - res = PQfn(conn, F_LO_LSEEK,&retval,&result_len,1,argv,3); + res = PQfn(conn, conn->lobjfuncs->fn_lo_lseek, + &retval,&result_len,1,argv,3); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; @@ -204,10 +239,17 @@ lo_creat(PGconn *conn, int mode) int retval; int result_len; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = mode; - res = PQfn(conn, F_LO_CREAT,&retval,&result_len,1,argv,1); + res = PQfn(conn, conn->lobjfuncs->fn_lo_creat, + &retval,&result_len,1,argv,1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return (Oid)retval; @@ -230,11 +272,18 @@ lo_tell(PGconn *conn, int fd) PGresult *res; int result_len; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = fd; - res = PQfn(conn, F_LO_TELL,&retval,&result_len,1,argv,1); + res = PQfn(conn, conn->lobjfuncs->fn_lo_tell, + &retval,&result_len,1,argv,1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; @@ -256,11 +305,18 @@ lo_unlink(PGconn *conn, Oid lobjId) int result_len; int retval; + if(conn->lobjfuncs == (PGlobjfuncs *)NULL) { + if(lo_initialize(conn) < 0) { + return -1; + } + } + argv[0].isint = 1; argv[0].len = 4; argv[0].u.integer = lobjId; - res = PQfn(conn, F_LO_UNLINK,&retval,&result_len,1,argv,1); + res = PQfn(conn, conn->lobjfuncs->fn_lo_unlink, + &retval,&result_len,1,argv,1); if (PQresultStatus(res) == PGRES_COMMAND_OK) { PQclear(res); return retval; @@ -380,3 +436,157 @@ lo_export(PGconn *conn, Oid lobjId, char *filename) return 1; } + + +/* ---------------- + * lo_initialize + * + * Initialize the large object interface for an existing connection. + * We ask the backend about the functions OID's in pg_proc for all + * functions that are required for large object operations. + * ---------------- + */ +static int lo_initialize(PGconn *conn) +{ + PGresult *res; + PGlobjfuncs *lobjfuncs; + int n; + char *fname; + Oid foid; + + /* ---------------- + * Allocate the structure to hold the functions OID's + * ---------------- + */ + lobjfuncs = (PGlobjfuncs *)malloc(sizeof(PGlobjfuncs)); + if (lobjfuncs == (PGlobjfuncs *)NULL) { + strcpy(conn->errorMessage, + "FATAL: malloc() failed in lo_initialize()\n"); + return -1; + } + memset((char *)lobjfuncs, 0, sizeof(PGlobjfuncs)); + + /* ---------------- + * Execute the query to get all the functions at once + * ---------------- + */ + res = PQexec(conn, "select proname, oid from pg_proc \ + where proname = 'lo_open' \ + or proname = 'lo_close' \ + or proname = 'lo_creat' \ + or proname = 'lo_unlink' \ + or proname = 'lo_lseek' \ + or proname = 'lo_tell' \ + or proname = 'LOread' \ + or proname = 'LOwrite'"); + if (res == (PGresult *)NULL) { + free(lobjfuncs); + return -1; + } + + if (res->resultStatus != PGRES_TUPLES_OK) { + free(lobjfuncs); + PQclear(res); + strcpy(conn->errorMessage, + "ERROR: SELECT didn't return data in lo_initialize()\n"); + return -1; + } + + /* ---------------- + * Examine the result and put the OID's into the struct + * ---------------- + */ + for(n = 0; n < PQntuples(res); n++) { + fname = PQgetvalue(res, n, 0); + foid = (Oid)atoi(PQgetvalue(res, n, 1)); + if(!strcmp(fname, "lo_open")) { + lobjfuncs->fn_lo_open = foid; + } else + if(!strcmp(fname, "lo_close")) { + lobjfuncs->fn_lo_close = foid; + } else + if(!strcmp(fname, "lo_creat")) { + lobjfuncs->fn_lo_creat = foid; + } else + if(!strcmp(fname, "lo_unlink")) { + lobjfuncs->fn_lo_unlink = foid; + } else + if(!strcmp(fname, "lo_lseek")) { + lobjfuncs->fn_lo_lseek = foid; + } else + if(!strcmp(fname, "lo_tell")) { + lobjfuncs->fn_lo_tell = foid; + } else + if(!strcmp(fname, "LOread")) { + lobjfuncs->fn_lo_read = foid; + } else + if(!strcmp(fname, "LOwrite")) { + lobjfuncs->fn_lo_write = foid; + } + } + + PQclear(res); + + /* ---------------- + * Finally check that we really got all large object + * interface functions. + * ---------------- + */ + if(lobjfuncs->fn_lo_open == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_open\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_close == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_close\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_creat == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_creat\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_unlink == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_unlink\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_lseek == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_lseek\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_tell == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function lo_tell\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_read == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function LOread\n"); + free(lobjfuncs); + return -1; + } + if(lobjfuncs->fn_lo_write == 0) { + strcpy(conn->errorMessage, + "ERROR: Cannot determine OID for function LOwrite\n"); + free(lobjfuncs); + return -1; + } + + /* ---------------- + * Put the structure into the connection control + * ---------------- + */ + conn->lobjfuncs = lobjfuncs; + return 0; +} + + diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h index 193497ea7d..f327b2d84c 100644 --- a/src/interfaces/libpq/libpq-fe.h +++ b/src/interfaces/libpq/libpq-fe.h @@ -6,7 +6,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: libpq-fe.h,v 1.11 1996/11/10 03:06:38 momjian Exp $ + * $Id: libpq-fe.h,v 1.12 1996/11/11 12:16:57 scrappy Exp $ * *------------------------------------------------------------------------- */ @@ -96,6 +96,17 @@ typedef struct pgNotify { int be_pid; /* process id of backend */ } PGnotify; +typedef struct pgLobjfuncs { + Oid fn_lo_open; /* OID of backend function lo_open */ + Oid fn_lo_close; /* OID of backend function lo_close */ + Oid fn_lo_creat; /* OID of backend function lo_creat */ + Oid fn_lo_unlink; /* OID of backend function lo_unlink */ + Oid fn_lo_lseek; /* OID of backend function lo_lseek */ + Oid fn_lo_tell; /* OID of backend function lo_tell */ + Oid fn_lo_read; /* OID of backend function LOread */ + Oid fn_lo_write; /* OID of backend function LOwrite */ +} PGlobjfuncs; + /* PGconn encapsulates a connection to the backend */ typedef struct pg_conn{ char *pghost; /* the machine on which the server is running */ @@ -113,6 +124,7 @@ typedef struct pg_conn{ int asyncNotifyWaiting; Dllist* notifyList; char *pguser; /* Postgres username of user who is connected */ + PGlobjfuncs *lobjfuncs; /* Backend function OID's for large object access */ } PGconn; #define CMDSTATUS_LEN 40 -- 2.40.0