// Java Interface to Postgres // $Id: PGlobj.java,v 1.1 1997/09/20 02:21:22 scrappy Exp $ // Copyright (c) 1997 Peter T Mount package postgresql; import java.sql.*; import java.math.*; import java.net.*; import java.io.*; import java.util.*; /** * This class implements the large object interface to postgresql. * * It provides the basic methods required to run the interface, plus * a pair of methods that provide InputStream and OutputStream classes * for this object. */ public class PGlobj { // This table contains the function oid's used by the backend private Hashtable func = new Hashtable(); protected postgresql.Connection conn; /** * These are the values for mode, taken from libpq-fs.h */ public static final int INV_ARCHIVE = 0x00010000; public static final int INV_WRITE = 0x00020000; public static final int INV_READ = 0x00040000; /** * These are the functions that implement the interface */ private static final String OPEN = "lo_open"; private static final String CLOSE = "lo_close"; private static final String CREATE = "lo_creat"; private static final String UNLINK = "lo_unlink"; private static final String SEEK = "lo_lseek"; private static final String TELL = "lo_tell"; private static final String READ = "loread"; private static final String WRITE = "lowrite"; /** * This creates the interface */ public PGlobj(Connection conn) throws SQLException { if(!(conn instanceof postgresql.Connection)) throw new SQLException("PGlobj: Wrong connection class"); this.conn = (postgresql.Connection)conn; ResultSet res = (postgresql.ResultSet)conn.createStatement().executeQuery("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==null) throw new SQLException("failed to initialise large object interface"); while(res.next()) { func.put(res.getString(1),new Integer(res.getInt(2))); DriverManager.println("PGlobj:func "+res.getString(1)+" oid="+res.getInt(2)); } res.close(); } // this returns the oid of the function private int getFunc(String name) throws SQLException { Integer i = (Integer)func.get(name); if(i==null) throw new SQLException("unknown function: "+name); return i.intValue(); } /** * This calls a function on the backend * @param fnid oid of the function to run * @param args array containing args, 3 ints per arg */ public int PQfn(int fnid,int args[]) throws SQLException { return PQfn(fnid,args,null,0,0); } // fix bug in 6.1.1 public void writeInt(DataOutputStream data,int i) throws IOException { data.writeByte((i>>24)&0xff); data.writeByte( i &0xff); data.writeByte((i>>8) &0xff); data.writeByte((i>>16)&0xff); } /** * This calls a function on the backend * @param fnid oid of the function to run * @param args array containing args, 3 ints per arg * @param buf byte array to write into, null returns result as an integer * @param off offset in array * @param len number of bytes to read */ public int PQfn(int fnid,int args[],byte buf[],int off,int len) throws SQLException { //ByteArrayOutputStream b = new ByteArrayOutputStream(); //DataOutputStream data = new DataOutputStream(b); int in = -1; try { int al=args.length/3; // For some reason, the backend takes these in the reverse order byte b[] = new byte[2+4+4]; int bp=0; b[bp++]='F'; b[bp++]=0; b[bp++]=(byte)((fnid)&0xff); b[bp++]=(byte)((fnid>>24)&0xff); b[bp++]=(byte)((fnid>>16)&0xff); b[bp++]=(byte)((fnid>>8)&0xff); b[bp++]=(byte)((al)&0xff); b[bp++]=(byte)((al>>24)&0xff); b[bp++]=(byte)((al>>16)&0xff); b[bp++]=(byte)((al>>8)&0xff); conn.pg_stream.Send(b); //conn.pg_stream.SendChar('F'); //conn.pg_stream.SendInteger(fnid,4); //conn.pg_stream.SendInteger(args.length / 3,4); int l = args.length-1; if(args[l]==0) l--; for(int i=0;irl) throw new IOException("mark invalidated"); obj.seek(fd,mp); } catch(SQLException e) { throw new IOException(e.toString()); } } public boolean markSupported() { return true; } public void close() throws IOException { try { obj.close(fd); } catch(SQLException e) { throw new IOException(e.toString()); } } } // This class implements an OutputStream to a large object class PGlobjOutput extends OutputStream { private PGlobj obj; private int fd; // This creates an Input stream based for a large object public PGlobjOutput(PGlobj obj,int fd) { this.obj = obj; this.fd = fd; } public void write(int i) throws IOException { byte b[] = new byte[1]; b[0] = (byte)i; write(b,0,1); } public void write(byte b[],int off,int len) throws IOException { try { obj.write(fd,b,off,len); } catch(SQLException e) { throw new IOException(e.toString()); } } public void close() throws IOException { try { obj.close(fd); } catch(SQLException e) { throw new IOException(e.toString()); } } }