mirror of https://github.com/postgres/postgres
parent
e9cd0f2e6b
commit
fa67a247cf
@ -0,0 +1,309 @@ |
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.lang.*; |
||||
import java.net.*; |
||||
import java.util.*; |
||||
import java.sql.*; |
||||
import postgresql.*; |
||||
|
||||
/** |
||||
* @version 1.0 15-APR-1997 |
||||
* |
||||
* This class is used by Connection & PGlobj for communicating with the |
||||
* backend. |
||||
* |
||||
* @see java.sql.Connection |
||||
*/ |
||||
// This class handles all the Streamed I/O for a postgresql connection
|
||||
public class PG_Stream |
||||
{ |
||||
private Socket connection; |
||||
private InputStream pg_input; |
||||
private OutputStream pg_output; |
||||
|
||||
/** |
||||
* Constructor: Connect to the PostgreSQL back end and return |
||||
* a stream connection. |
||||
* |
||||
* @param host the hostname to connect to |
||||
* @param port the port number that the postmaster is sitting on |
||||
* @exception IOException if an IOException occurs below it. |
||||
*/ |
||||
public PG_Stream(String host, int port) throws IOException |
||||
{ |
||||
connection = new Socket(host, port); |
||||
pg_input = connection.getInputStream(); |
||||
pg_output = connection.getOutputStream(); |
||||
} |
||||
|
||||
/** |
||||
* Sends a single character to the back end |
||||
* |
||||
* @param val the character to be sent |
||||
* @exception IOException if an I/O error occurs |
||||
*/ |
||||
public void SendChar(int val) throws IOException |
||||
{ |
||||
//pg_output.write(val);
|
||||
byte b[] = new byte[1]; |
||||
b[0] = (byte)val; |
||||
pg_output.write(b); |
||||
} |
||||
|
||||
/** |
||||
* Sends an integer to the back end |
||||
* |
||||
* @param val the integer to be sent |
||||
* @param siz the length of the integer in bytes (size of structure) |
||||
* @exception IOException if an I/O error occurs |
||||
*/ |
||||
public void SendInteger(int val, int siz) throws IOException |
||||
{ |
||||
byte[] buf = new byte[siz]; |
||||
|
||||
while (siz-- > 0) |
||||
{ |
||||
buf[siz] = (byte)(val & 0xff); |
||||
val >>= 8; |
||||
} |
||||
Send(buf); |
||||
} |
||||
|
||||
/** |
||||
* Send an array of bytes to the backend |
||||
* |
||||
* @param buf The array of bytes to be sent |
||||
* @exception IOException if an I/O error occurs |
||||
*/ |
||||
public void Send(byte buf[]) throws IOException |
||||
{ |
||||
pg_output.write(buf); |
||||
} |
||||
|
||||
/** |
||||
* Send an exact array of bytes to the backend - if the length |
||||
* has not been reached, send nulls until it has. |
||||
* |
||||
* @param buf the array of bytes to be sent |
||||
* @param siz the number of bytes to be sent |
||||
* @exception IOException if an I/O error occurs |
||||
*/ |
||||
public void Send(byte buf[], int siz) throws IOException |
||||
{ |
||||
Send(buf,0,siz); |
||||
} |
||||
|
||||
/** |
||||
* Send an exact array of bytes to the backend - if the length |
||||
* has not been reached, send nulls until it has. |
||||
* |
||||
* @param buf the array of bytes to be sent |
||||
* @param off offset in the array to start sending from |
||||
* @param siz the number of bytes to be sent |
||||
* @exception IOException if an I/O error occurs |
||||
*/ |
||||
public void Send(byte buf[], int off, int siz) throws IOException |
||||
{ |
||||
int i; |
||||
|
||||
pg_output.write(buf, off, ((buf.length-off) < siz ? (buf.length-off) : siz)); |
||||
if((buf.length-off) < siz) |
||||
{ |
||||
for (i = buf.length-off ; i < siz ; ++i) |
||||
{ |
||||
pg_output.write(0); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Receives a single character from the backend |
||||
* |
||||
* @return the character received |
||||
* @exception SQLException if an I/O Error returns |
||||
*/ |
||||
public int ReceiveChar() throws SQLException |
||||
{ |
||||
int c = 0; |
||||
|
||||
try |
||||
{ |
||||
c = pg_input.read(); |
||||
if (c < 0) throw new IOException("EOF"); |
||||
} catch (IOException e) { |
||||
throw new SQLException("Error reading from backend: " + e.toString()); |
||||
} |
||||
return c; |
||||
} |
||||
|
||||
/** |
||||
* Receives an integer from the backend |
||||
* |
||||
* @param siz length of the integer in bytes |
||||
* @return the integer received from the backend |
||||
* @exception SQLException if an I/O error occurs |
||||
*/ |
||||
public int ReceiveInteger(int siz) throws SQLException |
||||
{ |
||||
int n = 0; |
||||
|
||||
try |
||||
{ |
||||
for (int i = 0 ; i < siz ; i++) |
||||
{ |
||||
int b = pg_input.read(); |
||||
|
||||
if (b < 0) |
||||
throw new IOException("EOF"); |
||||
n = n | (b >> (8 * i)) ; |
||||
} |
||||
} catch (IOException e) { |
||||
throw new SQLException("Error reading from backend: " + e.toString()); |
||||
} |
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Receives a null-terminated string from the backend. Maximum of |
||||
* maxsiz bytes - if we don't see a null, then we assume something |
||||
* has gone wrong. |
||||
* |
||||
* @param maxsiz maximum length of string |
||||
* @return string from back end |
||||
* @exception SQLException if an I/O error occurs |
||||
*/ |
||||
public String ReceiveString(int maxsiz) throws SQLException |
||||
{ |
||||
byte[] rst = new byte[maxsiz]; |
||||
int s = 0; |
||||
|
||||
try |
||||
{ |
||||
while (s < maxsiz) |
||||
{ |
||||
int c = pg_input.read(); |
||||
if (c < 0) |
||||
throw new IOException("EOF"); |
||||
else if (c == 0) |
||||
break; |
||||
else |
||||
rst[s++] = (byte)c; |
||||
} |
||||
if (s >= maxsiz) |
||||
throw new IOException("Too Much Data"); |
||||
} catch (IOException e) { |
||||
throw new SQLException("Error reading from backend: " + e.toString()); |
||||
} |
||||
String v = new String(rst, 0, s); |
||||
return v; |
||||
} |
||||
|
||||
/** |
||||
* Read a tuple from the back end. A tuple is a two dimensional |
||||
* array of bytes |
||||
* |
||||
* @param nf the number of fields expected |
||||
* @param bin true if the tuple is a binary tuple |
||||
* @return null if the current response has no more tuples, otherwise |
||||
* an array of strings |
||||
* @exception SQLException if a data I/O error occurs |
||||
*/ |
||||
public byte[][] ReceiveTuple(int nf, boolean bin) throws SQLException |
||||
{ |
||||
int i, bim = (nf + 7)/8; |
||||
byte[] bitmask = Receive(bim); |
||||
byte[][] answer = new byte[nf][0]; |
||||
|
||||
int whichbit = 0x80; |
||||
int whichbyte = 0; |
||||
|
||||
for (i = 0 ; i < nf ; ++i) |
||||
{ |
||||
boolean isNull = ((bitmask[whichbyte] & whichbit) == 0); |
||||
whichbit >>= 1; |
||||
if (whichbit == 0) |
||||
{ |
||||
++whichbyte; |
||||
whichbit = 0x80; |
||||
} |
||||
if (isNull) |
||||
answer[i] = null; |
||||
else |
||||
{ |
||||
int len = ReceiveInteger(4); |
||||
if (!bin) |
||||
len -= 4; |
||||
if (len < 0) |
||||
len = 0; |
||||
answer[i] = Receive(len); |
||||
} |
||||
} |
||||
return answer; |
||||
} |
||||
|
||||
/** |
||||
* Reads in a given number of bytes from the backend |
||||
* |
||||
* @param siz number of bytes to read |
||||
* @return array of bytes received |
||||
* @exception SQLException if a data I/O error occurs |
||||
*/ |
||||
private byte[] Receive(int siz) throws SQLException |
||||
{ |
||||
byte[] answer = new byte[siz]; |
||||
int s = 0; |
||||
|
||||
try |
||||
{ |
||||
while (s < siz) |
||||
{ |
||||
int w = pg_input.read(answer, s, siz - s); |
||||
if (w < 0) |
||||
throw new IOException("EOF"); |
||||
s += w; |
||||
} |
||||
} catch (IOException e) { |
||||
throw new SQLException("Error reading from backend: " + e.toString()); |
||||
} |
||||
return answer; |
||||
} |
||||
|
||||
/** |
||||
* Reads in a given number of bytes from the backend |
||||
* |
||||
* @param buf buffer to store result |
||||
* @param off offset in buffer |
||||
* @param siz number of bytes to read |
||||
* @exception SQLException if a data I/O error occurs |
||||
*/ |
||||
public void Receive(byte[] b,int off,int siz) throws SQLException |
||||
{ |
||||
int s = 0; |
||||
|
||||
try |
||||
{ |
||||
while (s < siz) |
||||
{ |
||||
int w = pg_input.read(b, off+s, siz - s); |
||||
if (w < 0) |
||||
throw new IOException("EOF"); |
||||
s += w; |
||||
} |
||||
} catch (IOException e) { |
||||
throw new SQLException("Error reading from backend: " + e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Closes the connection |
||||
* |
||||
* @exception IOException if a IO Error occurs |
||||
*/ |
||||
public void close() throws IOException |
||||
{ |
||||
pg_output.close(); |
||||
pg_input.close(); |
||||
connection.close(); |
||||
} |
||||
} |
||||
@ -0,0 +1,59 @@ |
||||
/** |
||||
* @version 6.2 |
||||
* |
||||
* This implements a box consisting of two points |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGbox implements Serializable |
||||
{ |
||||
/** |
||||
* These are the two points. |
||||
*/ |
||||
public PGpoint point[] = new PGpoint[2]; |
||||
|
||||
public PGbox(double x1,double y1,double x2,double y2) |
||||
{ |
||||
this.point[0] = new PGpoint(x1,y1); |
||||
this.point[1] = new PGpoint(x2,y2); |
||||
} |
||||
|
||||
public PGbox(PGpoint p1,PGpoint p2) |
||||
{ |
||||
this.point[0] = p1; |
||||
this.point[1] = p2; |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGbox(String s) throws SQLException |
||||
{ |
||||
PGtokenizer t = new PGtokenizer(s,','); |
||||
if(t.getSize() != 2) |
||||
throw new SQLException("conversion of box failed - "+s); |
||||
|
||||
point[0] = new PGpoint(t.getToken(0)); |
||||
point[1] = new PGpoint(t.getToken(1)); |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGbox p = (PGbox)obj; |
||||
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) || |
||||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0])); |
||||
} |
||||
|
||||
/** |
||||
* This returns the lseg in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
return point[0].toString()+","+point[1].toString(); |
||||
} |
||||
} |
||||
@ -0,0 +1,72 @@ |
||||
/** |
||||
* |
||||
* This implements a circle consisting of a point and a radius |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGcircle implements Serializable |
||||
{ |
||||
/** |
||||
* This is the centre point |
||||
*/ |
||||
public PGpoint center; |
||||
|
||||
/** |
||||
* This is the radius |
||||
*/ |
||||
double radius; |
||||
|
||||
public PGcircle(double x,double y,double r) |
||||
{ |
||||
this.center = new PGpoint(x,y); |
||||
this.radius = r; |
||||
} |
||||
|
||||
public PGcircle(PGpoint c,double r) |
||||
{ |
||||
this.center = c; |
||||
this.radius = r; |
||||
} |
||||
|
||||
public PGcircle(PGcircle c) |
||||
{ |
||||
this.center = new PGpoint(c.center); |
||||
this.radius = c.radius; |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGcircle(String s) throws SQLException |
||||
{ |
||||
PGtokenizer t = new PGtokenizer(PGtokenizer.removeAngle(s),','); |
||||
if(t.getSize() != 2) |
||||
throw new SQLException("conversion of circle failed - "+s); |
||||
|
||||
try { |
||||
center = new PGpoint(t.getToken(0)); |
||||
radius = Double.valueOf(t.getToken(1)).doubleValue(); |
||||
} catch(NumberFormatException e) { |
||||
throw new SQLException("conversion of circle failed - "+s+" - +"+e.toString()); |
||||
} |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGcircle p = (PGcircle)obj; |
||||
return p.center.equals(center) && p.radius==radius; |
||||
} |
||||
|
||||
/** |
||||
* This returns the circle in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
return "<"+center+","+radius+">"; |
||||
} |
||||
} |
||||
@ -0,0 +1,462 @@ |
||||
// 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;i<l;i++) |
||||
conn.pg_stream.SendInteger(args[i],4); |
||||
|
||||
if(args[args.length-1]==0) |
||||
conn.pg_stream.Send(buf,off,len); |
||||
|
||||
} catch(Exception e) { |
||||
throw new SQLException("lo_open failed"); |
||||
} |
||||
//try {
|
||||
if((in = conn.pg_stream.ReceiveChar())!='V') { |
||||
if(in=='E') |
||||
throw new SQLException(conn.pg_stream.ReceiveString(4096)); |
||||
throw new SQLException("lobj: expected 'V' from backend, got "+((char)in)); |
||||
} |
||||
|
||||
while(true) { |
||||
in = conn.pg_stream.ReceiveChar(); |
||||
switch(in) |
||||
{ |
||||
case 'G': |
||||
if(buf==null) |
||||
in = conn.pg_stream.ReceiveInteger(4); |
||||
else |
||||
conn.pg_stream.Receive(buf,off,len); |
||||
conn.pg_stream.ReceiveChar(); |
||||
return in; |
||||
|
||||
case 'E': |
||||
throw new SQLException("lobj: error - "+conn.pg_stream.ReceiveString(4096)); |
||||
|
||||
case 'N': |
||||
conn.pg_stream.ReceiveString(4096); |
||||
break; |
||||
|
||||
case '0': |
||||
return -1; |
||||
|
||||
default: |
||||
throw new SQLException("lobj: protocol error"); |
||||
} |
||||
} |
||||
// } catch(IOException ioe) {
|
||||
// throw new SQLException("lobj: Network error - "+ioe);
|
||||
//}
|
||||
} |
||||
|
||||
/** |
||||
* This opens a large object. It returns a handle that is used to |
||||
* access the object. |
||||
*/ |
||||
public int open(int lobjId,int mode) throws SQLException |
||||
{ |
||||
int args[] = new int[2*3]; |
||||
args[0] = args[3] = 4; |
||||
args[1] = args[4] = 1; |
||||
args[2] = lobjId; |
||||
args[5] = mode; |
||||
|
||||
int fd = PQfn(getFunc(OPEN),args); |
||||
if(fd<0) |
||||
throw new SQLException("lo_open: no object"); |
||||
seek(fd,0); |
||||
return fd; |
||||
} |
||||
|
||||
/** |
||||
* This closes a large object. |
||||
*/ |
||||
public void close(int fd) throws SQLException |
||||
{ |
||||
int args[] = new int[1*3]; |
||||
args[0] = 4; |
||||
args[1] = 1; |
||||
args[2] = fd; |
||||
|
||||
// flush/close streams here?
|
||||
PQfn(getFunc(CLOSE),args); |
||||
} |
||||
|
||||
/** |
||||
* This reads a block of bytes from the large object |
||||
* @param fd descriptor for an open large object |
||||
* @param buf byte array to write into |
||||
* @param off offset in array |
||||
* @param len number of bytes to read |
||||
*/ |
||||
public void read(int fd,byte buf[],int off,int len) throws SQLException |
||||
{ |
||||
int args[] = new int[2*3]; |
||||
args[0] = args[3] = 4; |
||||
args[1] = args[4] = 1; |
||||
args[2] = fd; |
||||
args[5] = len; |
||||
|
||||
PQfn(getFunc(READ),args,buf,off,len); |
||||
} |
||||
|
||||
/** |
||||
* This writes a block of bytes to an open large object |
||||
* @param fd descriptor for an open large object |
||||
* @param buf byte array to write into |
||||
* @param off offset in array |
||||
* @param len number of bytes to read |
||||
*/ |
||||
public void write(int fd,byte buf[],int off,int len) throws SQLException |
||||
{ |
||||
int args[] = new int[2*3]; |
||||
args[0] = args[3] = 4; |
||||
args[1] = args[4] = 1; |
||||
args[2] = fd; |
||||
args[5] = 0; |
||||
|
||||
PQfn(getFunc(WRITE),args,buf,off,len); |
||||
} |
||||
|
||||
/** |
||||
* This sets the current read or write location on a large object. |
||||
* @param fd descriptor of an open large object |
||||
* @param off offset in object |
||||
*/ |
||||
public void seek(int fd,int off) throws SQLException |
||||
{ |
||||
int args[] = new int[3*3]; |
||||
args[0] = args[3] = args[6] = 4; |
||||
args[1] = args[4] = args[7] = 1; |
||||
args[2] = fd; |
||||
args[5] = off; |
||||
args[8] = 0; // SEEK
|
||||
|
||||
PQfn(getFunc(SEEK),args); |
||||
} |
||||
|
||||
/** |
||||
* This creates a new large object. |
||||
* |
||||
* the mode is a bitmask describing different attributes of the new object |
||||
* |
||||
* returns the oid of the large object created. |
||||
*/ |
||||
public int create(int mode) throws SQLException |
||||
{ |
||||
int args[] = new int[1*3]; |
||||
args[0] = 4; |
||||
args[1] = 1; |
||||
args[2] = mode; |
||||
|
||||
return PQfn(getFunc(CREATE),args); |
||||
} |
||||
|
||||
/** |
||||
* This returns the current location within the large object |
||||
*/ |
||||
public int tell(int fd) throws SQLException |
||||
{ |
||||
int args[] = new int[1*3]; |
||||
args[0] = 4; |
||||
args[1] = 1; |
||||
args[2] = fd; |
||||
|
||||
return PQfn(getFunc(TELL),args); |
||||
} |
||||
|
||||
/** |
||||
* This removes a large object from the database |
||||
*/ |
||||
public void unlink(int fd) throws SQLException |
||||
{ |
||||
int args[] = new int[1*3]; |
||||
args[0] = 4; |
||||
args[1] = 1; |
||||
args[2] = fd; |
||||
|
||||
PQfn(getFunc(UNLINK),args); |
||||
} |
||||
|
||||
/** |
||||
* This returns an InputStream based on an object |
||||
*/ |
||||
public InputStream getInputStream(int fd) throws SQLException |
||||
{ |
||||
return (InputStream) new PGlobjInput(this,fd); |
||||
} |
||||
|
||||
/** |
||||
* This returns an OutputStream based on an object |
||||
*/ |
||||
public OutputStream getOutputStream(int fd) throws SQLException |
||||
{ |
||||
return (OutputStream) new PGlobjOutput(this,fd); |
||||
} |
||||
|
||||
/** |
||||
* As yet, the lo_import and lo_export functions are not implemented. |
||||
*/ |
||||
} |
||||
|
||||
// This class implements an InputStream based on a large object
|
||||
//
|
||||
// Note: Unlike most InputStreams, this one supports mark()/reset()
|
||||
//
|
||||
class PGlobjInput extends InputStream |
||||
{ |
||||
private PGlobj obj; |
||||
private int fd; |
||||
|
||||
private int mp; // mark position
|
||||
private int rl; // read limit
|
||||
|
||||
// This creates an Input stream based for a large object
|
||||
public PGlobjInput(PGlobj obj,int fd) |
||||
{ |
||||
this.obj = obj; |
||||
this.fd = fd; |
||||
} |
||||
|
||||
public int read() throws IOException |
||||
{ |
||||
byte b[] = new byte[1]; |
||||
read(b,0,1); |
||||
return (int)b[0]; |
||||
} |
||||
|
||||
public int read(byte b[],int off,int len) throws IOException |
||||
{ |
||||
try { |
||||
obj.read(fd,b,off,len); |
||||
} catch(SQLException e) { |
||||
throw new IOException(e.toString()); |
||||
} |
||||
return len; |
||||
} |
||||
|
||||
public long skip(long n) throws IOException |
||||
{ |
||||
try { |
||||
int cp = obj.tell(fd); |
||||
obj.seek(fd,cp+(int)n); |
||||
return obj.tell(fd) - cp; |
||||
} catch(SQLException e) { |
||||
throw new IOException(e.toString()); |
||||
} |
||||
} |
||||
|
||||
public synchronized void mark(int readLimit) |
||||
{ |
||||
try { |
||||
mp = obj.tell(fd); |
||||
rl = readLimit; |
||||
} catch(SQLException e) { |
||||
// We should throw an exception here, but mark() doesn't ;-(
|
||||
} |
||||
} |
||||
|
||||
public void reset() throws IOException |
||||
{ |
||||
try { |
||||
int cp = obj.tell(fd); |
||||
if((cp-mp)>rl) |
||||
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()); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,58 @@ |
||||
/** |
||||
* |
||||
* This implements a lseg (line segment) consisting of two points |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGlseg implements Serializable |
||||
{ |
||||
/** |
||||
* These are the two points. |
||||
*/ |
||||
public PGpoint point[] = new PGpoint[2]; |
||||
|
||||
public PGlseg(double x1,double y1,double x2,double y2) |
||||
{ |
||||
this.point[0] = new PGpoint(x1,y1); |
||||
this.point[1] = new PGpoint(x2,y2); |
||||
} |
||||
|
||||
public PGlseg(PGpoint p1,PGpoint p2) |
||||
{ |
||||
this.point[0] = p1; |
||||
this.point[1] = p2; |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGlseg(String s) throws SQLException |
||||
{ |
||||
PGtokenizer t = new PGtokenizer(PGtokenizer.removeBox(s),','); |
||||
if(t.getSize() != 2) |
||||
throw new SQLException("conversion of lseg failed - "+s); |
||||
|
||||
point[0] = new PGpoint(t.getToken(0)); |
||||
point[1] = new PGpoint(t.getToken(1)); |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGlseg p = (PGlseg)obj; |
||||
return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) || |
||||
(p.point[0].equals(point[1]) && p.point[1].equals(point[0])); |
||||
} |
||||
|
||||
/** |
||||
* This returns the lseg in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
return "["+point[0]+","+point[1]+"]"; |
||||
} |
||||
} |
||||
@ -0,0 +1,99 @@ |
||||
/** |
||||
* |
||||
* This implements a path (a multiple segmented line, which may be closed) |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGpath implements Serializable |
||||
{ |
||||
public int npoints; |
||||
public boolean open; |
||||
public PGpoint point[]; |
||||
|
||||
public PGpath(int num,PGpoint[] points,boolean open) |
||||
{ |
||||
npoints = num; |
||||
this.point = points; |
||||
this.open = open; |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGpath(String s) throws SQLException |
||||
{ |
||||
// First test to see if were open
|
||||
if(s.startsWith("[") && s.endsWith("]")) { |
||||
open = true; |
||||
s = PGtokenizer.removeBox(s); |
||||
} else if(s.startsWith("(") && s.endsWith(")")) { |
||||
open = false; |
||||
s = PGtokenizer.removePara(s); |
||||
} else |
||||
throw new SQLException("cannot tell if path is open or closed"); |
||||
|
||||
PGtokenizer t = new PGtokenizer(s,','); |
||||
npoints = t.getSize(); |
||||
point = new PGpoint[npoints]; |
||||
for(int p=0;p<npoints;p++) |
||||
point[p] = new PGpoint(t.getToken(p)); |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGpath p = (PGpath)obj; |
||||
|
||||
if(p.npoints != npoints) |
||||
return false; |
||||
|
||||
if(p.open != open) |
||||
return false; |
||||
|
||||
for(int i=0;i<npoints;i++) |
||||
if(!point[i].equals(p.point[i])) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* This returns the polygon in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
StringBuffer b = new StringBuffer(open?"[":"("); |
||||
|
||||
for(int p=0;p<npoints;p++) |
||||
b.append(point[p].toString()); |
||||
|
||||
b.append(open?"]":")"); |
||||
|
||||
return b.toString(); |
||||
} |
||||
|
||||
public boolean isOpen() |
||||
{ |
||||
return open; |
||||
} |
||||
|
||||
public boolean isClosed() |
||||
{ |
||||
return !open; |
||||
} |
||||
|
||||
public void closePath() |
||||
{ |
||||
open = false; |
||||
} |
||||
|
||||
public void openPath() |
||||
{ |
||||
open = true; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,96 @@ |
||||
/** |
||||
* |
||||
* This implements a version of java.awt.Point, except it uses double |
||||
* to represent the coordinates. |
||||
* |
||||
* It maps to the point datatype in postgresql. |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.awt.Point; |
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGpoint implements Serializable |
||||
{ |
||||
/** |
||||
* These are the coordinates. |
||||
* These are public, because their equivalents in java.awt.Point are |
||||
*/ |
||||
public double x,y; |
||||
|
||||
public PGpoint(double x,double y) |
||||
{ |
||||
this.x = x; |
||||
this.y = y; |
||||
} |
||||
|
||||
public PGpoint(PGpoint p) |
||||
{ |
||||
this(p.x,p.y); |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGpoint(String s) throws SQLException |
||||
{ |
||||
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s),','); |
||||
try { |
||||
x = Double.valueOf(t.getToken(0)).doubleValue(); |
||||
y = Double.valueOf(t.getToken(1)).doubleValue(); |
||||
} catch(NumberFormatException e) { |
||||
throw new SQLException("conversion of point failed - "+e.toString()); |
||||
} |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGpoint p = (PGpoint)obj; |
||||
return x == p.x && y == p.y; |
||||
} |
||||
|
||||
/** |
||||
* This returns the point in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
return "("+x+","+y+")"; |
||||
} |
||||
|
||||
public void translate(int x,int y) |
||||
{ |
||||
translate((double)x,(double)y); |
||||
} |
||||
|
||||
public void translate(double x,double y) |
||||
{ |
||||
this.x += x; |
||||
this.y += y; |
||||
} |
||||
|
||||
public void move(int x,int y) |
||||
{ |
||||
setLocation(x,y); |
||||
} |
||||
|
||||
public void move(double x,double y) |
||||
{ |
||||
this.x = x; |
||||
this.y = y; |
||||
} |
||||
|
||||
// refer to java.awt.Point for description of this
|
||||
public void setLocation(int x,int y) |
||||
{ |
||||
move((double)x,(double)y); |
||||
} |
||||
|
||||
// refer to java.awt.Point for description of this
|
||||
public void setLocation(Point p) |
||||
{ |
||||
setLocation(p.x,p.y); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@ |
||||
/** |
||||
* |
||||
* This implements a polygon (based on java.awt.Polygon) |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.io.*; |
||||
import java.sql.*; |
||||
|
||||
public class PGpolygon implements Serializable |
||||
{ |
||||
public int npoints; |
||||
|
||||
public PGpoint point[]; |
||||
|
||||
public PGpolygon(int num,PGpoint[] points) |
||||
{ |
||||
npoints = num; |
||||
this.point = points; |
||||
} |
||||
|
||||
/** |
||||
* This constructor is used by the driver. |
||||
*/ |
||||
public PGpolygon(String s) throws SQLException |
||||
{ |
||||
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s),','); |
||||
npoints = t.getSize(); |
||||
point = new PGpoint[npoints]; |
||||
for(int p=0;p<npoints;p++) |
||||
point[p] = new PGpoint(t.getToken(p)); |
||||
} |
||||
|
||||
public boolean equals(Object obj) |
||||
{ |
||||
PGpolygon p = (PGpolygon)obj; |
||||
|
||||
if(p.npoints != npoints) |
||||
return false; |
||||
|
||||
for(int i=0;i<npoints;i++) |
||||
if(!point[i].equals(p.point[i])) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* This returns the polygon in the syntax expected by postgresql |
||||
*/ |
||||
public String toString() |
||||
{ |
||||
StringBuffer b = new StringBuffer(); |
||||
for(int p=0;p<npoints;p++) |
||||
b.append(point[p].toString()); |
||||
return b.toString(); |
||||
} |
||||
} |
||||
@ -0,0 +1,100 @@ |
||||
/** |
||||
* |
||||
* This class is used to tokenize the text output of postgres. |
||||
* |
||||
*/ |
||||
|
||||
package postgresql; |
||||
|
||||
import java.sql.*; |
||||
import java.util.*; |
||||
|
||||
public class PGtokenizer |
||||
{ |
||||
protected Vector tokens; |
||||
|
||||
public PGtokenizer(String string,char delim) |
||||
{ |
||||
tokenize(string,delim); |
||||
} |
||||
|
||||
/** |
||||
* Tokenizes a new string |
||||
*/ |
||||
public int tokenize(String string,char delim) |
||||
{ |
||||
tokens = new Vector(); |
||||
|
||||
int nest=0,p,s; |
||||
for(p=0,s=0;p<string.length();p++) { |
||||
char c = string.charAt(p); |
||||
|
||||
// increase nesting if an open character is found
|
||||
if(c == '(' || c == '[') |
||||
nest++; |
||||
|
||||
// decrease nesting if a close character is found
|
||||
if(c == ')' || c == ']') |
||||
nest--; |
||||
|
||||
if(nest==0 && c==delim) { |
||||
tokens.addElement(string.substring(s,p)); |
||||
s=p+1; // +1 to skip the delimiter
|
||||
} |
||||
|
||||
} |
||||
|
||||
// Don't forget the last token ;-)
|
||||
if(s<string.length()) |
||||
tokens.addElement(string.substring(s)); |
||||
|
||||
return tokens.size(); |
||||
} |
||||
|
||||
public int getSize() |
||||
{ |
||||
return tokens.size(); |
||||
} |
||||
|
||||
public String getToken(int n) |
||||
{ |
||||
return (String)tokens.elementAt(n); |
||||
} |
||||
|
||||
/** |
||||
* This returns a new tokenizer based on one of our tokens |
||||
*/ |
||||
public PGtokenizer tokenizeToken(int n,char delim) |
||||
{ |
||||
return new PGtokenizer(getToken(n),delim); |
||||
} |
||||
|
||||
/** |
||||
* This removes the lead/trailing strings from a string |
||||
*/ |
||||
public static String remove(String s,String l,String t) |
||||
{ |
||||
if(s.startsWith(l)) s = s.substring(l.length()); |
||||
if(s.endsWith(t)) s = s.substring(0,s.length()-t.length()); |
||||
return s; |
||||
} |
||||
|
||||
/** |
||||
* This removes the lead/trailing strings from all tokens |
||||
*/ |
||||
public void remove(String l,String t) |
||||
{ |
||||
for(int i=0;i<tokens.size();i++) { |
||||
tokens.setElementAt(remove((String)tokens.elementAt(i),l,t),i); |
||||
} |
||||
} |
||||
|
||||
public static String removePara(String s) {return remove(s,"(",")");} |
||||
public void removePara() {remove("(",")");} |
||||
|
||||
public static String removeBox(String s) {return remove(s,"[","]");} |
||||
public void removeBox() {remove("[","]");} |
||||
|
||||
public static String removeAngle(String s) {return remove(s,"<",">");} |
||||
public void removeAngle() {remove("<",">");} |
||||
} |
||||
Loading…
Reference in new issue