mirror of
https://github.com/postgres/postgres.git
synced 2025-12-06 00:02:13 +03:00
Oops...missed over half the patch :(
This commit is contained in:
291
src/interfaces/jdbc/postgresql/fastpath/Fastpath.java
Normal file
291
src/interfaces/jdbc/postgresql/fastpath/Fastpath.java
Normal file
@@ -0,0 +1,291 @@
|
||||
package postgresql.fastpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This class implements the Fastpath api.
|
||||
*
|
||||
* <p>This is a means of executing functions imbeded in the postgresql backend
|
||||
* from within a java application.
|
||||
*
|
||||
* <p>It is based around the file src/interfaces/libpq/fe-exec.c
|
||||
*
|
||||
*
|
||||
* <p><b>Implementation notes:</b>
|
||||
*
|
||||
* <p><b><em>Network protocol:</em></b>
|
||||
*
|
||||
* <p>The code within the backend reads integers in reverse.
|
||||
*
|
||||
* <p>There is work in progress to convert all of the protocol to
|
||||
* network order but it may not be there for v6.3
|
||||
*
|
||||
* <p>When fastpath switches, simply replace SendIntegerReverse() with
|
||||
* SendInteger()
|
||||
*
|
||||
* @see postgresql.FastpathFastpathArg
|
||||
* @see postgresql.LargeObject
|
||||
*/
|
||||
public class Fastpath
|
||||
{
|
||||
// This maps the functions names to their id's (possible unique just
|
||||
// to a connection).
|
||||
protected Hashtable func = new Hashtable();
|
||||
|
||||
protected postgresql.Connection conn; // our connection
|
||||
protected postgresql.PG_Stream stream; // the network stream
|
||||
|
||||
/**
|
||||
* Initialises the fastpath system
|
||||
*
|
||||
* <p><b>Important Notice</b>
|
||||
* <br>This is called from postgresql.Connection, and should not be called
|
||||
* from client code.
|
||||
*
|
||||
* @param conn postgresql.Connection to attach to
|
||||
* @param stream The network stream to the backend
|
||||
*/
|
||||
public Fastpath(postgresql.Connection conn,postgresql.PG_Stream stream)
|
||||
{
|
||||
this.conn=conn;
|
||||
this.stream=stream;
|
||||
DriverManager.println("Fastpath initialised");
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a function call to the PostgreSQL backend
|
||||
*
|
||||
* @param fnid Function id
|
||||
* @param resulttype True if the result is an integer, false for other results
|
||||
* @param args FastpathArguments to pass to fastpath
|
||||
* @return null if no data, Integer if an integer result, or byte[] otherwise
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public Object fastpath(int fnid,boolean resulttype,FastpathArg[] args) throws SQLException
|
||||
{
|
||||
// send the function call
|
||||
try {
|
||||
// 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
|
||||
// that confuses the backend. The 0 terminates the command line.
|
||||
stream.SendInteger(70,1);
|
||||
stream.SendInteger(0,1);
|
||||
|
||||
stream.SendIntegerReverse(fnid,4);
|
||||
stream.SendIntegerReverse(args.length,4);
|
||||
|
||||
for(int i=0;i<args.length;i++)
|
||||
args[i].send(stream);
|
||||
|
||||
// This is needed, otherwise data can be lost
|
||||
stream.flush();
|
||||
|
||||
} catch(IOException ioe) {
|
||||
throw new SQLException("Failed to send fastpath call "+fnid+"\n"+ioe);
|
||||
}
|
||||
|
||||
// Now handle the result
|
||||
|
||||
// We should get 'V' on sucess or 'E' on error. Anything else is treated
|
||||
// as an error.
|
||||
//int in = stream.ReceiveChar();
|
||||
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
|
||||
//if(in!='V') {
|
||||
//if(in=='E')
|
||||
//throw new SQLException(stream.ReceiveString(4096));
|
||||
//throw new SQLException("Fastpath: expected 'V' from backend, got "+((char)in));
|
||||
//}
|
||||
|
||||
// Now loop, reading the results
|
||||
Object result = null; // our result
|
||||
while(true) {
|
||||
int in = stream.ReceiveChar();
|
||||
DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
|
||||
switch(in)
|
||||
{
|
||||
case 'V':
|
||||
break;
|
||||
|
||||
//------------------------------
|
||||
// Function returned properly
|
||||
//
|
||||
case 'G':
|
||||
int sz = stream.ReceiveInteger(4);
|
||||
DriverManager.println("G: size="+sz); //debug
|
||||
|
||||
// Return an Integer if
|
||||
if(resulttype)
|
||||
result = new Integer(stream.ReceiveInteger(sz));
|
||||
else {
|
||||
byte buf[] = new byte[sz];
|
||||
stream.Receive(buf,0,sz);
|
||||
result = buf;
|
||||
}
|
||||
break;
|
||||
|
||||
//------------------------------
|
||||
// Error message returned
|
||||
case 'E':
|
||||
throw new SQLException("Fastpath: "+stream.ReceiveString(4096));
|
||||
|
||||
//------------------------------
|
||||
// Notice from backend
|
||||
case 'N':
|
||||
conn.addWarning(stream.ReceiveString(4096));
|
||||
break;
|
||||
|
||||
//------------------------------
|
||||
// End of results
|
||||
//
|
||||
// Here we simply return res, which would contain the result
|
||||
// processed earlier. If no result, this already contains null
|
||||
case '0':
|
||||
DriverManager.println("returning "+result);
|
||||
return result;
|
||||
|
||||
default:
|
||||
throw new SQLException("Fastpath: protocol error. Got '"+((char)in)+"'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a function call to the PostgreSQL backend by name.
|
||||
*
|
||||
* Note: the mapping for the procedure name to function id needs to exist,
|
||||
* usually to an earlier call to addfunction().
|
||||
*
|
||||
* This is the prefered method to call, as function id's can/may change
|
||||
* between versions of the backend.
|
||||
*
|
||||
* For an example of how this works, refer to postgresql.LargeObject
|
||||
*
|
||||
* @param name Function name
|
||||
* @param resulttype True if the result is an integer, false for other
|
||||
* results
|
||||
* @param args FastpathArguments to pass to fastpath
|
||||
* @return null if no data, Integer if an integer result, or byte[] otherwise
|
||||
* @exception SQLException if name is unknown or if a database-access error
|
||||
* occurs.
|
||||
* @see postgresql.LargeObject
|
||||
*/
|
||||
public Object fastpath(String name,boolean resulttype,FastpathArg[] args) throws SQLException
|
||||
{
|
||||
DriverManager.println("Fastpath: calling "+name);
|
||||
return fastpath(getID(name),resulttype,args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This convenience method assumes that the return value is an Integer
|
||||
* @param name Function name
|
||||
* @param args Function arguments
|
||||
* @return integer result
|
||||
* @exception SQLException if a database-access error occurs or no result
|
||||
*/
|
||||
public int getInteger(String name,FastpathArg[] args) throws SQLException
|
||||
{
|
||||
Integer i = (Integer)fastpath(name,true,args);
|
||||
if(i==null)
|
||||
throw new SQLException("Fastpath:"+name+": no result returned, expected integer");
|
||||
return i.intValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* This convenience method assumes that the return value is an Integer
|
||||
* @param name Function name
|
||||
* @param args Function arguments
|
||||
* @return byte[] array containing result
|
||||
* @exception SQLException if a database-access error occurs or no result
|
||||
*/
|
||||
public byte[] getData(String name,FastpathArg[] args) throws SQLException
|
||||
{
|
||||
return (byte[])fastpath(name,false,args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This adds a function to our lookup table.
|
||||
*
|
||||
* <p>User code should use the addFunctions method, which is based upon a
|
||||
* query, rather than hard coding the oid. The oid for a function is not
|
||||
* guaranteed to remain static, even on different servers of the same
|
||||
* version.
|
||||
*
|
||||
* @param name Function name
|
||||
* @param fnid Function id
|
||||
*/
|
||||
public void addFunction(String name,int fnid)
|
||||
{
|
||||
func.put(name,new Integer(fnid));
|
||||
}
|
||||
|
||||
/**
|
||||
* This takes a ResultSet containing two columns. Column 1 contains the
|
||||
* function name, Column 2 the oid.
|
||||
*
|
||||
* <p>It reads the entire ResultSet, loading the values into the function
|
||||
* table.
|
||||
*
|
||||
* <p><b>REMEMBER</b> to close() the resultset after calling this!!
|
||||
*
|
||||
* <p><b><em>Implementation note about function name lookups:</em></b>
|
||||
*
|
||||
* <p>PostgreSQL stores the function id's and their corresponding names in
|
||||
* the pg_proc table. To speed things up locally, instead of querying each
|
||||
* function from that table when required, a Hashtable is used. Also, only
|
||||
* the function's required are entered into this table, keeping connection
|
||||
* times as fast as possible.
|
||||
*
|
||||
* <p>The postgresql.LargeObject class performs a query upon it's startup,
|
||||
* and passes the returned ResultSet to the addFunctions() method here.
|
||||
*
|
||||
* <p>Once this has been done, the LargeObject api refers to the functions by
|
||||
* name.
|
||||
*
|
||||
* <p>Dont think that manually converting them to the oid's will work. Ok,
|
||||
* they will for now, but they can change during development (there was some
|
||||
* discussion about this for V7.0), so this is implemented to prevent any
|
||||
* unwarranted headaches in the future.
|
||||
*
|
||||
* @param rs ResultSet
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
* @see postgresql.LargeObjectManager
|
||||
*/
|
||||
public void addFunctions(ResultSet rs) throws SQLException
|
||||
{
|
||||
while(rs.next()) {
|
||||
func.put(rs.getString(1),new Integer(rs.getInt(2)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the function id associated by its name
|
||||
*
|
||||
* <p>If addFunction() or addFunctions() have not been called for this name,
|
||||
* then an SQLException is thrown.
|
||||
*
|
||||
* @param name Function name to lookup
|
||||
* @return Function ID for fastpath call
|
||||
* @exception SQLException is function is unknown.
|
||||
*/
|
||||
public int getID(String name) throws SQLException
|
||||
{
|
||||
Integer id = (Integer)func.get(name);
|
||||
|
||||
// may be we could add a lookup to the database here, and store the result
|
||||
// in our lookup table, throwing the exception if that fails.
|
||||
// We must, however, ensure that if we do, any existing ResultSet is
|
||||
// unaffected, otherwise we could break user code.
|
||||
//
|
||||
// so, until we know we can do this (needs testing, on the TODO list)
|
||||
// for now, we throw the exception and do no lookups.
|
||||
if(id==null)
|
||||
throw new SQLException("Fastpath: function "+name+" is unknown");
|
||||
|
||||
return id.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
106
src/interfaces/jdbc/postgresql/fastpath/FastpathArg.java
Normal file
106
src/interfaces/jdbc/postgresql/fastpath/FastpathArg.java
Normal file
@@ -0,0 +1,106 @@
|
||||
package postgresql.fastpath;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* Each fastpath call requires an array of arguments, the number and type
|
||||
* dependent on the function being called.
|
||||
*
|
||||
* <p>This class implements methods needed to provide this capability.
|
||||
*
|
||||
* <p>For an example on how to use this, refer to the postgresql.largeobject
|
||||
* package
|
||||
*
|
||||
* @see postgresql.fastpath.Fastpath
|
||||
* @see postgresql.largeobject.LargeObjectManager
|
||||
* @see postgresql.largeobject.LargeObject
|
||||
*/
|
||||
public class FastpathArg
|
||||
{
|
||||
/**
|
||||
* Type of argument, true=integer, false=byte[]
|
||||
*/
|
||||
public boolean type;
|
||||
|
||||
/**
|
||||
* Integer value if type=true
|
||||
*/
|
||||
public int value;
|
||||
|
||||
/**
|
||||
* Byte value if type=false;
|
||||
*/
|
||||
public byte[] bytes;
|
||||
|
||||
/**
|
||||
* Constructs an argument that consists of an integer value
|
||||
* @param value int value to set
|
||||
*/
|
||||
public FastpathArg(int value)
|
||||
{
|
||||
type=true;
|
||||
this.value=value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an argument that consists of an array of bytes
|
||||
* @param bytes array to store
|
||||
*/
|
||||
public FastpathArg(byte bytes[])
|
||||
{
|
||||
type=false;
|
||||
this.bytes=bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an argument that consists of part of a byte array
|
||||
* @param buf source array
|
||||
* @param off offset within array
|
||||
* @param len length of data to include
|
||||
*/
|
||||
public FastpathArg(byte buf[],int off,int len)
|
||||
{
|
||||
type=false;
|
||||
bytes = new byte[len];
|
||||
System.arraycopy(buf,off,bytes,0,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an argument that consists of a String.
|
||||
* @param s String to store
|
||||
*/
|
||||
public FastpathArg(String s)
|
||||
{
|
||||
this(s.getBytes());
|
||||
}
|
||||
|
||||
/**
|
||||
* This sends this argument down the network stream.
|
||||
*
|
||||
* <p>The stream sent consists of the length.int4 then the contents.
|
||||
*
|
||||
* <p><b>Note:</b> This is called from Fastpath, and cannot be called from
|
||||
* client code.
|
||||
*
|
||||
* @param s output stream
|
||||
* @exception IOException if something failed on the network stream
|
||||
*/
|
||||
protected void send(postgresql.PG_Stream s) throws IOException
|
||||
{
|
||||
if(type) {
|
||||
// argument is an integer
|
||||
s.SendIntegerReverse(4,4); // size of an integer
|
||||
s.SendIntegerReverse(value,4); // integer value of argument
|
||||
} else {
|
||||
// argument is a byte array
|
||||
s.SendIntegerReverse(bytes.length,4); // size of array
|
||||
s.Send(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
105
src/interfaces/jdbc/postgresql/geometric/PGbox.java
Normal file
105
src/interfaces/jdbc/postgresql/geometric/PGbox.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This represents the box datatype within postgresql.
|
||||
*/
|
||||
public class PGbox extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* These are the two points.
|
||||
*/
|
||||
public PGpoint point[] = new PGpoint[2];
|
||||
|
||||
/**
|
||||
* @param x1 first x coordinate
|
||||
* @param y1 first y coordinate
|
||||
* @param x2 second x coordinate
|
||||
* @param y2 second y coordinate
|
||||
*/
|
||||
public PGbox(double x1,double y1,double x2,double y2)
|
||||
{
|
||||
this();
|
||||
this.point[0] = new PGpoint(x1,y1);
|
||||
this.point[1] = new PGpoint(x2,y2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p1 first point
|
||||
* @param p2 second point
|
||||
*/
|
||||
public PGbox(PGpoint p1,PGpoint p2)
|
||||
{
|
||||
this();
|
||||
this.point[0] = p1;
|
||||
this.point[1] = p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Box definition in PostgreSQL syntax
|
||||
* @exception SQLException if definition is invalid
|
||||
*/
|
||||
public PGbox(String s) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required constructor
|
||||
*/
|
||||
public PGbox()
|
||||
{
|
||||
setType("box");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the value of this object. It should be overidden,
|
||||
* but still called by subclasses.
|
||||
*
|
||||
* @param value a string representation of the value of the object
|
||||
* @exception SQLException thrown if value is invalid for this type
|
||||
*/
|
||||
public void setValue(String value) throws SQLException
|
||||
{
|
||||
PGtokenizer t = new PGtokenizer(value,',');
|
||||
if(t.getSize() != 2)
|
||||
throw new SQLException("conversion of box failed - "+value);
|
||||
|
||||
point[0] = new PGpoint(t.getToken(0));
|
||||
point[1] = new PGpoint(t.getToken(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGbox) {
|
||||
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]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
return new PGbox((PGpoint)point[0].clone(),(PGpoint)point[1].clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the PGbox in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return point[0].toString()+","+point[1].toString();
|
||||
}
|
||||
}
|
||||
108
src/interfaces/jdbc/postgresql/geometric/PGcircle.java
Normal file
108
src/interfaces/jdbc/postgresql/geometric/PGcircle.java
Normal file
@@ -0,0 +1,108 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This represents postgresql's circle datatype, consisting of a point and
|
||||
* a radius
|
||||
*/
|
||||
public class PGcircle extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* This is the centre point
|
||||
*/
|
||||
public PGpoint center;
|
||||
|
||||
/**
|
||||
* This is the radius
|
||||
*/
|
||||
double radius;
|
||||
|
||||
/**
|
||||
* @param x coordinate of centre
|
||||
* @param y coordinate of centre
|
||||
* @param r radius of circle
|
||||
*/
|
||||
public PGcircle(double x,double y,double r)
|
||||
{
|
||||
this(new PGpoint(x,y),r);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param c PGpoint describing the circle's centre
|
||||
* @param r radius of circle
|
||||
*/
|
||||
public PGcircle(PGpoint c,double r)
|
||||
{
|
||||
this();
|
||||
this.center = c;
|
||||
this.radius = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s definition of the circle in PostgreSQL's syntax.
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public PGcircle(String s) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor is used by the driver.
|
||||
*/
|
||||
public PGcircle()
|
||||
{
|
||||
setType("circle");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s definition of the circle in PostgreSQL's syntax.
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public void setValue(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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGcircle) {
|
||||
PGcircle p = (PGcircle)obj;
|
||||
return p.center.equals(center) && p.radius==radius;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
return new PGcircle((PGpoint)center.clone(),radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the PGcircle in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return "<"+center+","+radius+">";
|
||||
}
|
||||
}
|
||||
100
src/interfaces/jdbc/postgresql/geometric/PGlseg.java
Normal file
100
src/interfaces/jdbc/postgresql/geometric/PGlseg.java
Normal file
@@ -0,0 +1,100 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This implements a lseg (line segment) consisting of two points
|
||||
*/
|
||||
public class PGlseg extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* These are the two points.
|
||||
*/
|
||||
public PGpoint point[] = new PGpoint[2];
|
||||
|
||||
/**
|
||||
* @param x1 coordinate for first point
|
||||
* @param y1 coordinate for first point
|
||||
* @param x2 coordinate for second point
|
||||
* @param y2 coordinate for second point
|
||||
*/
|
||||
public PGlseg(double x1,double y1,double x2,double y2)
|
||||
{
|
||||
this(new PGpoint(x1,y1),new PGpoint(x2,y2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param p1 first point
|
||||
* @param p2 second point
|
||||
*/
|
||||
public PGlseg(PGpoint p1,PGpoint p2)
|
||||
{
|
||||
this();
|
||||
this.point[0] = p1;
|
||||
this.point[1] = p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s definition of the circle in PostgreSQL's syntax.
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public PGlseg(String s) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* reuired by the driver
|
||||
*/
|
||||
public PGlseg()
|
||||
{
|
||||
setType("lseg");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Definition of the line segment in PostgreSQL's syntax
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public void setValue(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));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGlseg) {
|
||||
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]));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
return new PGlseg((PGpoint)point[0].clone(),(PGpoint)point[1].clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the PGlseg in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return "["+point[0]+","+point[1]+"]";
|
||||
}
|
||||
}
|
||||
145
src/interfaces/jdbc/postgresql/geometric/PGpath.java
Normal file
145
src/interfaces/jdbc/postgresql/geometric/PGpath.java
Normal file
@@ -0,0 +1,145 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This implements a path (a multiple segmented line, which may be closed)
|
||||
*/
|
||||
public class PGpath extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* True if the path is open, false if closed
|
||||
*/
|
||||
public boolean open;
|
||||
|
||||
/**
|
||||
* The points defining this path
|
||||
*/
|
||||
public PGpoint points[];
|
||||
|
||||
/**
|
||||
* @param points the PGpoints that define the path
|
||||
* @param open True if the path is open, false if closed
|
||||
*/
|
||||
public PGpath(PGpoint[] points,boolean open)
|
||||
{
|
||||
this();
|
||||
this.points = points;
|
||||
this.open = open;
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by the driver
|
||||
*/
|
||||
public PGpath()
|
||||
{
|
||||
setType("path");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s definition of the circle in PostgreSQL's syntax.
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public PGpath(String s) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Definition of the path in PostgreSQL's syntax
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public void setValue(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,',');
|
||||
int npoints = t.getSize();
|
||||
points = new PGpoint[npoints];
|
||||
for(int p=0;p<npoints;p++)
|
||||
points[p] = new PGpoint(t.getToken(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGpath) {
|
||||
PGpath p = (PGpath)obj;
|
||||
|
||||
if(p.points.length != points.length)
|
||||
return false;
|
||||
|
||||
if(p.open != open)
|
||||
return false;
|
||||
|
||||
for(int i=0;i<points.length;i++)
|
||||
if(!points[i].equals(p.points[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
PGpoint ary[] = new PGpoint[points.length];
|
||||
for(int i=0;i<points.length;i++)
|
||||
ary[i]=(PGpoint)points[i].clone();
|
||||
return new PGpath(ary,open);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the polygon in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
StringBuffer b = new StringBuffer(open?"[":"(");
|
||||
|
||||
for(int p=0;p<points.length;p++) {
|
||||
if(p>0) b.append(",");
|
||||
b.append(points[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;
|
||||
}
|
||||
|
||||
}
|
||||
167
src/interfaces/jdbc/postgresql/geometric/PGpoint.java
Normal file
167
src/interfaces/jdbc/postgresql/geometric/PGpoint.java
Normal file
@@ -0,0 +1,167 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This implements a version of java.awt.Point, except it uses double
|
||||
* to represent the coordinates.
|
||||
*
|
||||
* <p>It maps to the point datatype in postgresql.
|
||||
*/
|
||||
public class PGpoint extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* The X coordinate of the point
|
||||
*/
|
||||
public double x;
|
||||
|
||||
/**
|
||||
* The Y coordinate of the point
|
||||
*/
|
||||
public double y;
|
||||
|
||||
/**
|
||||
* @param x coordinate
|
||||
* @param y coordinate
|
||||
*/
|
||||
public PGpoint(double x,double y)
|
||||
{
|
||||
this();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called mainly from the other geometric types, when a
|
||||
* point is imbeded within their definition.
|
||||
*
|
||||
* @param value Definition of this point in PostgreSQL's syntax
|
||||
*/
|
||||
public PGpoint(String value) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by the driver
|
||||
*/
|
||||
public PGpoint()
|
||||
{
|
||||
setType("point");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Definition of this point in PostgreSQL's syntax
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public void setValue(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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGpoint) {
|
||||
PGpoint p = (PGpoint)obj;
|
||||
return x == p.x && y == p.y;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
return new PGpoint(x,y);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the PGpoint in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return "("+x+","+y+")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the point with the supplied amount.
|
||||
* @param x integer amount to add on the x axis
|
||||
* @param y integer amount to add on the y axis
|
||||
*/
|
||||
public void translate(int x,int y)
|
||||
{
|
||||
translate((double)x,(double)y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate the point with the supplied amount.
|
||||
* @param x double amount to add on the x axis
|
||||
* @param y double amount to add on the y axis
|
||||
*/
|
||||
public void translate(double x,double y)
|
||||
{
|
||||
this.x += x;
|
||||
this.y += y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the point to the supplied coordinates.
|
||||
* @param x integer coordinate
|
||||
* @param y integer coordinate
|
||||
*/
|
||||
public void move(int x,int y)
|
||||
{
|
||||
setLocation(x,y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the point to the supplied coordinates.
|
||||
* @param x double coordinate
|
||||
* @param y double coordinate
|
||||
*/
|
||||
public void move(double x,double y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the point to the supplied coordinates.
|
||||
* refer to java.awt.Point for description of this
|
||||
* @param x integer coordinate
|
||||
* @param y integer coordinate
|
||||
* @see java.awt.Point
|
||||
*/
|
||||
public void setLocation(int x,int y)
|
||||
{
|
||||
move((double)x,(double)y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the point to the supplied java.awt.Point
|
||||
* refer to java.awt.Point for description of this
|
||||
* @param p Point to move to
|
||||
* @see java.awt.Point
|
||||
*/
|
||||
public void setLocation(Point p)
|
||||
{
|
||||
setLocation(p.x,p.y);
|
||||
}
|
||||
|
||||
}
|
||||
105
src/interfaces/jdbc/postgresql/geometric/PGpolygon.java
Normal file
105
src/interfaces/jdbc/postgresql/geometric/PGpolygon.java
Normal file
@@ -0,0 +1,105 @@
|
||||
package postgresql.geometric;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.*;
|
||||
import postgresql.util.*;
|
||||
|
||||
/**
|
||||
* This implements the polygon datatype within PostgreSQL.
|
||||
*/
|
||||
public class PGpolygon extends PGobject implements Serializable,Cloneable
|
||||
{
|
||||
/**
|
||||
* The points defining the polygon
|
||||
*/
|
||||
public PGpoint points[];
|
||||
|
||||
/**
|
||||
* Creates a polygon using an array of PGpoints
|
||||
*
|
||||
* @param points the points defining the polygon
|
||||
*/
|
||||
public PGpolygon(PGpoint[] points)
|
||||
{
|
||||
this();
|
||||
this.points = points;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s definition of the circle in PostgreSQL's syntax.
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public PGpolygon(String s) throws SQLException
|
||||
{
|
||||
this();
|
||||
setValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Required by the driver
|
||||
*/
|
||||
public PGpolygon()
|
||||
{
|
||||
setType("polygon");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param s Definition of the polygon in PostgreSQL's syntax
|
||||
* @exception SQLException on conversion failure
|
||||
*/
|
||||
public void setValue(String s) throws SQLException
|
||||
{
|
||||
PGtokenizer t = new PGtokenizer(PGtokenizer.removePara(s),',');
|
||||
int npoints = t.getSize();
|
||||
points = new PGpoint[npoints];
|
||||
for(int p=0;p<npoints;p++)
|
||||
points[p] = new PGpoint(t.getToken(p));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGpolygon) {
|
||||
PGpolygon p = (PGpolygon)obj;
|
||||
|
||||
if(p.points.length != points.length)
|
||||
return false;
|
||||
|
||||
for(int i=0;i<points.length;i++)
|
||||
if(!points[i].equals(p.points[i]))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
PGpoint ary[] = new PGpoint[points.length];
|
||||
for(int i=0;i<points.length;i++)
|
||||
ary[i] = (PGpoint)points[i].clone();
|
||||
return new PGpolygon(ary);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the PGpolygon in the syntax expected by postgresql
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
StringBuffer b = new StringBuffer();
|
||||
b.append("(");
|
||||
for(int p=0;p<points.length;p++) {
|
||||
if(p>0) b.append(",");
|
||||
b.append(points[p].toString());
|
||||
}
|
||||
b.append(")");
|
||||
return b.toString();
|
||||
}
|
||||
}
|
||||
253
src/interfaces/jdbc/postgresql/largeobject/LargeObject.java
Normal file
253
src/interfaces/jdbc/postgresql/largeobject/LargeObject.java
Normal file
@@ -0,0 +1,253 @@
|
||||
package postgresql.largeobject;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
|
||||
import postgresql.fastpath.*;
|
||||
|
||||
/**
|
||||
* This class implements the large object interface to postgresql.
|
||||
*
|
||||
* <p>It provides the basic methods required to run the interface, plus
|
||||
* a pair of methods that provide InputStream and OutputStream classes
|
||||
* for this object.
|
||||
*
|
||||
* <p>Normally, client code would use the getAsciiStream, getBinaryStream,
|
||||
* or getUnicodeStream methods in ResultSet, or setAsciiStream,
|
||||
* setBinaryStream, or setUnicodeStream methods in PreparedStatement to
|
||||
* access Large Objects.
|
||||
*
|
||||
* <p>However, sometimes lower level access to Large Objects are required,
|
||||
* that are not supported by the JDBC specification.
|
||||
*
|
||||
* <p>Refer to postgresql.largeobject.LargeObjectManager on how to gain access
|
||||
* to a Large Object, or how to create one.
|
||||
*
|
||||
* @see postgresql.largeobject.LargeObjectManager
|
||||
* @see postgresql.ResultSet#getAsciiStream
|
||||
* @see postgresql.ResultSet#getBinaryStream
|
||||
* @see postgresql.ResultSet#getUnicodeStream
|
||||
* @see postgresql.PreparedStatement#setAsciiStream
|
||||
* @see postgresql.PreparedStatement#setBinaryStream
|
||||
* @see postgresql.PreparedStatement#setUnicodeStream
|
||||
* @see java.sql.ResultSet#getAsciiStream
|
||||
* @see java.sql.ResultSet#getBinaryStream
|
||||
* @see java.sql.ResultSet#getUnicodeStream
|
||||
* @see java.sql.PreparedStatement#setAsciiStream
|
||||
* @see java.sql.PreparedStatement#setBinaryStream
|
||||
* @see java.sql.PreparedStatement#setUnicodeStream
|
||||
*
|
||||
*/
|
||||
public class LargeObject
|
||||
{
|
||||
/**
|
||||
* Indicates a seek from the begining of a file
|
||||
*/
|
||||
public static final int SEEK_SET = 0;
|
||||
|
||||
/**
|
||||
* Indicates a seek from the current position
|
||||
*/
|
||||
public static final int SEEK_CUR = 1;
|
||||
|
||||
/**
|
||||
* Indicates a seek from the end of a file
|
||||
*/
|
||||
public static final int SEEK_END = 2;
|
||||
|
||||
private Fastpath fp; // Fastpath API to use
|
||||
private int oid; // OID of this object
|
||||
private int fd; // the descriptor of the open large object
|
||||
|
||||
/**
|
||||
* This opens a large object.
|
||||
*
|
||||
* <p>If the object does not exist, then an SQLException is thrown.
|
||||
*
|
||||
* @param fp FastPath API for the connection to use
|
||||
* @param oid of the Large Object to open
|
||||
* @param mode Mode of opening the large object
|
||||
* (defined in LargeObjectManager)
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
* @see postgresql.largeobject.LargeObjectManager
|
||||
*/
|
||||
protected LargeObject(Fastpath fp,int oid,int mode) throws SQLException
|
||||
{
|
||||
this.fp = fp;
|
||||
this.oid = oid;
|
||||
|
||||
FastpathArg args[] = new FastpathArg[2];
|
||||
args[0] = new FastpathArg(oid);
|
||||
args[1] = new FastpathArg(mode);
|
||||
this.fd = fp.getInteger("lo_open",args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the OID of this LargeObject
|
||||
*/
|
||||
public int getOID()
|
||||
{
|
||||
return oid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method closes the object. You must not call methods in this
|
||||
* object after this is called.
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void close() throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[1];
|
||||
args[0] = new FastpathArg(fd);
|
||||
fp.fastpath("lo_close",false,args); // true here as we dont care!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads some data from the object, and return as a byte[] array
|
||||
*
|
||||
* @param len number of bytes to read
|
||||
* @return byte[] array containing data read
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public byte[] read(int len) throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[2];
|
||||
args[0] = new FastpathArg(fd);
|
||||
args[1] = new FastpathArg(len);
|
||||
return fp.getData("loread",args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads some data from the object into an existing array
|
||||
*
|
||||
* @param buf destination array
|
||||
* @param off offset within array
|
||||
* @param len number of bytes to read
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void read(byte buf[],int off,int len) throws SQLException
|
||||
{
|
||||
System.arraycopy(read(len),0,buf,off,len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an array to the object
|
||||
*
|
||||
* @param buf array to write
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void write(byte buf[]) throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[2];
|
||||
args[0] = new FastpathArg(fd);
|
||||
args[1] = new FastpathArg(buf);
|
||||
fp.fastpath("lowrite",false,args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes some data from an array to the object
|
||||
*
|
||||
* @param buf destination array
|
||||
* @param off offset within array
|
||||
* @param len number of bytes to write
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void write(byte buf[],int off,int len) throws SQLException
|
||||
{
|
||||
byte data[] = new byte[len];
|
||||
System.arraycopy(buf,off,data,0,len);
|
||||
write(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current position within the object.
|
||||
*
|
||||
* <p>This is similar to the fseek() call in the standard C library. It
|
||||
* allows you to have random access to the large object.
|
||||
*
|
||||
* @param pos position within object
|
||||
* @param ref Either SEEK_SET, SEEK_CUR or SEEK_END
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void seek(int pos,int ref) throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[3];
|
||||
args[0] = new FastpathArg(fd);
|
||||
args[1] = new FastpathArg(pos);
|
||||
args[2] = new FastpathArg(ref);
|
||||
fp.fastpath("lo_lseek",false,args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current position within the object.
|
||||
*
|
||||
* <p>This is similar to the fseek() call in the standard C library. It
|
||||
* allows you to have random access to the large object.
|
||||
*
|
||||
* @param pos position within object from begining
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public void seek(int pos) throws SQLException
|
||||
{
|
||||
seek(pos,SEEK_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the current position within the object
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public int tell() throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[1];
|
||||
args[0] = new FastpathArg(fd);
|
||||
return fp.getInteger("lo_tell",args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is inefficient, as the only way to find out the size of
|
||||
* the object is to seek to the end, record the current position, then
|
||||
* return to the original position.
|
||||
*
|
||||
* <p>A better method will be found in the future.
|
||||
*
|
||||
* @return the size of the large object
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public int size() throws SQLException
|
||||
{
|
||||
int cp = tell();
|
||||
seek(0,SEEK_END);
|
||||
int sz = tell();
|
||||
seek(cp,SEEK_SET);
|
||||
return sz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an InputStream from this object.
|
||||
*
|
||||
* <p>This InputStream can then be used in any method that requires an
|
||||
* InputStream.
|
||||
*
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public InputStream getInputStream() throws SQLException
|
||||
{
|
||||
throw new SQLException("LargeObject:getInputStream not implemented");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an OutputStream to this object
|
||||
*
|
||||
* <p>This OutputStream can then be used in any method that requires an
|
||||
* OutputStream.
|
||||
*
|
||||
* @exception SQLException if a database-access error occurs.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws SQLException
|
||||
{
|
||||
throw new SQLException("LargeObject:getOutputStream not implemented");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package postgresql.largeobject;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.sql.*;
|
||||
|
||||
import postgresql.fastpath.*;
|
||||
|
||||
/**
|
||||
* This class implements the large object interface to postgresql.
|
||||
*
|
||||
* <p>It provides methods that allow client code to create, open and delete
|
||||
* large objects from the database. When opening an object, an instance of
|
||||
* postgresql.largeobject.LargeObject is returned, and its methods then allow
|
||||
* access to the object.
|
||||
*
|
||||
* <p>This class can only be created by postgresql.Connection
|
||||
*
|
||||
* <p>To get access to this class, use the following segment of code:
|
||||
* <br><pre>
|
||||
* import postgresql.largeobject.*;
|
||||
*
|
||||
* Connection conn;
|
||||
* LargeObjectManager lobj;
|
||||
*
|
||||
* ... code that opens a connection ...
|
||||
*
|
||||
* lobj = ((postgresql.Connection)myconn).getLargeObjectAPI();
|
||||
* </pre>
|
||||
*
|
||||
* <p>Normally, client code would use the getAsciiStream, getBinaryStream,
|
||||
* or getUnicodeStream methods in ResultSet, or setAsciiStream,
|
||||
* setBinaryStream, or setUnicodeStream methods in PreparedStatement to
|
||||
* access Large Objects.
|
||||
*
|
||||
* <p>However, sometimes lower level access to Large Objects are required,
|
||||
* that are not supported by the JDBC specification.
|
||||
*
|
||||
* <p>Refer to postgresql.largeobject.LargeObject on how to manipulate the
|
||||
* contents of a Large Object.
|
||||
*
|
||||
* @see postgresql.largeobject.LargeObject
|
||||
* @see postgresql.ResultSet#getAsciiStream
|
||||
* @see postgresql.ResultSet#getBinaryStream
|
||||
* @see postgresql.ResultSet#getUnicodeStream
|
||||
* @see postgresql.PreparedStatement#setAsciiStream
|
||||
* @see postgresql.PreparedStatement#setBinaryStream
|
||||
* @see postgresql.PreparedStatement#setUnicodeStream
|
||||
* @see java.sql.ResultSet#getAsciiStream
|
||||
* @see java.sql.ResultSet#getBinaryStream
|
||||
* @see java.sql.ResultSet#getUnicodeStream
|
||||
* @see java.sql.PreparedStatement#setAsciiStream
|
||||
* @see java.sql.PreparedStatement#setBinaryStream
|
||||
* @see java.sql.PreparedStatement#setUnicodeStream
|
||||
*/
|
||||
public class LargeObjectManager
|
||||
{
|
||||
// the fastpath api for this connection
|
||||
private Fastpath fp;
|
||||
|
||||
/**
|
||||
* This mode indicates we want to write to an object
|
||||
*/
|
||||
public static final int WRITE = 0x00020000;
|
||||
|
||||
/**
|
||||
* This mode indicates we want to read an object
|
||||
*/
|
||||
public static final int READ = 0x00040000;
|
||||
|
||||
/**
|
||||
* This mode is the default. It indicates we want read and write access to
|
||||
* a large object
|
||||
*/
|
||||
public static final int READWRITE = READ | WRITE;
|
||||
|
||||
/**
|
||||
* This prevents us being created by mere mortals
|
||||
*/
|
||||
private LargeObjectManager()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs the LargeObject API.
|
||||
*
|
||||
* <p><b>Important Notice</b>
|
||||
* <br>This method should only be called by postgresql.Connection
|
||||
*
|
||||
* <p>There should only be one LargeObjectManager per Connection. The
|
||||
* postgresql.Connection class keeps track of the various extension API's
|
||||
* and it's advised you use those to gain access, and not going direct.
|
||||
*/
|
||||
public LargeObjectManager(postgresql.Connection conn) throws SQLException
|
||||
{
|
||||
// We need Fastpath to do anything
|
||||
this.fp = conn.getFastpathAPI();
|
||||
|
||||
// Now get the function oid's for the api
|
||||
//
|
||||
// This is an example of Fastpath.addFunctions();
|
||||
//
|
||||
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 LargeObject API");
|
||||
|
||||
fp.addFunctions(res);
|
||||
res.close();
|
||||
DriverManager.println("Large Object initialised");
|
||||
}
|
||||
|
||||
/**
|
||||
* This opens an existing large object, based on its OID. This method
|
||||
* assumes that READ and WRITE access is required (the default).
|
||||
*
|
||||
* @param oid of large object
|
||||
* @return LargeObject instance providing access to the object
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public LargeObject open(int oid) throws SQLException
|
||||
{
|
||||
return new LargeObject(fp,oid,READWRITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This opens an existing large object, based on its OID
|
||||
*
|
||||
* @param oid of large object
|
||||
* @param mode mode of open
|
||||
* @return LargeObject instance providing access to the object
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public LargeObject open(int oid,int mode) throws SQLException
|
||||
{
|
||||
return new LargeObject(fp,oid,mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a large object, returning its OID.
|
||||
*
|
||||
* <p>It defaults to READWRITE for the new object's attributes.
|
||||
*
|
||||
* @return oid of new object
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public int create() throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[1];
|
||||
args[0] = new FastpathArg(READWRITE);
|
||||
return fp.getInteger("lo_creat",args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a large object, returning its OID
|
||||
*
|
||||
* @param mode a bitmask describing different attributes of the new object
|
||||
* @return oid of new object
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public int create(int mode) throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[1];
|
||||
args[0] = new FastpathArg(mode);
|
||||
return fp.getInteger("lo_creat",args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes a large object.
|
||||
*
|
||||
* @param oid describing object to delete
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public void delete(int oid) throws SQLException
|
||||
{
|
||||
FastpathArg args[] = new FastpathArg[1];
|
||||
args[0] = new FastpathArg(oid);
|
||||
fp.fastpath("lo_unlink",false,args);
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes a large object.
|
||||
*
|
||||
* <p>It is identical to the delete method, and is supplied as the C API uses
|
||||
* unlink.
|
||||
*
|
||||
* @param oid describing object to delete
|
||||
* @exception SQLException on error
|
||||
*/
|
||||
public void unlink(int oid) throws SQLException
|
||||
{
|
||||
delete(oid);
|
||||
}
|
||||
|
||||
}
|
||||
102
src/interfaces/jdbc/postgresql/util/PGobject.java
Normal file
102
src/interfaces/jdbc/postgresql/util/PGobject.java
Normal file
@@ -0,0 +1,102 @@
|
||||
package postgresql.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.*;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* postgresql.PG_Object is a class used to describe unknown types
|
||||
* An unknown type is any type that is unknown by JDBC Standards
|
||||
*
|
||||
* <p>As of PostgreSQL 6.3, this allows user code to add their own
|
||||
* handlers via a call to postgresql.Connection. These handlers
|
||||
* must extend this class.
|
||||
*/
|
||||
public class PGobject implements Serializable,Cloneable
|
||||
{
|
||||
protected String type;
|
||||
protected String value;
|
||||
|
||||
/**
|
||||
* This is called by postgresql.Connection.getObject() to create the
|
||||
* object.
|
||||
*/
|
||||
public PGobject()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the type of this object.
|
||||
*
|
||||
* <p>It should not be extended by subclasses, hence its final
|
||||
*
|
||||
* @param type a string describing the type of the object
|
||||
*/
|
||||
public final void setType(String type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method sets the value of this object. It must be overidden.
|
||||
*
|
||||
* @param value a string representation of the value of the object
|
||||
* @exception SQLException thrown if value is invalid for this type
|
||||
*/
|
||||
public void setValue(String value) throws SQLException
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* As this cannot change during the life of the object, it's final.
|
||||
* @return the type name of this object
|
||||
*/
|
||||
public final String getType()
|
||||
{
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden, to return the value of the object, in the
|
||||
* form required by postgresql.
|
||||
* @return the value of this object
|
||||
*/
|
||||
public String getValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow comparisons of objects
|
||||
* @param obj Object to compare with
|
||||
* @return true if the two boxes are identical
|
||||
*/
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if(obj instanceof PGobject)
|
||||
return ((PGobject)obj).getValue().equals(getValue());
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* This must be overidden to allow the object to be cloned
|
||||
*/
|
||||
public Object clone()
|
||||
{
|
||||
PGobject obj = new PGobject();
|
||||
obj.type=type;
|
||||
obj.value=value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is defined here, so user code need not overide it.
|
||||
* @return the value of this object, in the syntax expected by postgresql
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
197
src/interfaces/jdbc/postgresql/util/PGtokenizer.java
Normal file
197
src/interfaces/jdbc/postgresql/util/PGtokenizer.java
Normal file
@@ -0,0 +1,197 @@
|
||||
package postgresql.util;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* This class is used to tokenize the text output of postgres.
|
||||
*
|
||||
* <p>It's mainly used by the geometric classes, but is useful in parsing any
|
||||
* output from custom data types output from postgresql.
|
||||
*
|
||||
* @see postgresql.geometric.PGbox
|
||||
* @see postgresql.geometric.PGcircle
|
||||
* @see postgresql.geometric.PGlseg
|
||||
* @see postgresql.geometric.PGpath
|
||||
* @see postgresql.geometric.PGpoint
|
||||
* @see postgresql.geometric.PGpolygon
|
||||
*/
|
||||
public class PGtokenizer
|
||||
{
|
||||
// Our tokens
|
||||
protected Vector tokens;
|
||||
|
||||
/**
|
||||
* Create a tokeniser.
|
||||
*
|
||||
* <p>We could have used StringTokenizer to do this, however, we needed to
|
||||
* handle nesting of '(' ')' '[' ']' '<' and '>' as these are used
|
||||
* by the geometric data types.
|
||||
*
|
||||
* @param string containing tokens
|
||||
* @param delim single character to split the tokens
|
||||
*/
|
||||
public PGtokenizer(String string,char delim)
|
||||
{
|
||||
tokenize(string,delim);
|
||||
}
|
||||
|
||||
/**
|
||||
* This resets this tokenizer with a new string and/or delimiter.
|
||||
*
|
||||
* @param string containing tokens
|
||||
* @param delim single character to split the tokens
|
||||
*/
|
||||
public int tokenize(String string,char delim)
|
||||
{
|
||||
tokens = new Vector();
|
||||
|
||||
// nest holds how many levels we are in the current token.
|
||||
// if this is > 0 then we don't split a token when delim is matched.
|
||||
//
|
||||
// The Geometric datatypes use this, because often a type may have others
|
||||
// (usualls PGpoint) imbedded within a token.
|
||||
//
|
||||
// Peter 1998 Jan 6 - Added < and > to the nesting rules
|
||||
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 == '[' || c == '<')
|
||||
nest++;
|
||||
|
||||
// decrease nesting if a close character is found
|
||||
if(c == ')' || 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of tokens available
|
||||
*/
|
||||
public int getSize()
|
||||
{
|
||||
return tokens.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param n Token number ( 0 ... getSize()-1 )
|
||||
* @return The token value
|
||||
*/
|
||||
public String getToken(int n)
|
||||
{
|
||||
return (String)tokens.elementAt(n);
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns a new tokenizer based on one of our tokens.
|
||||
*
|
||||
* The geometric datatypes use this to process nested tokens (usually
|
||||
* PGpoint).
|
||||
*
|
||||
* @param n Token number ( 0 ... getSize()-1 )
|
||||
* @param delim The delimiter to use
|
||||
* @return A new instance of PGtokenizer based on the token
|
||||
*/
|
||||
public PGtokenizer tokenizeToken(int n,char delim)
|
||||
{
|
||||
return new PGtokenizer(getToken(n),delim);
|
||||
}
|
||||
|
||||
/**
|
||||
* This removes the lead/trailing strings from a string
|
||||
* @param s Source string
|
||||
* @param l Leading string to remove
|
||||
* @param t Trailing string to remove
|
||||
* @return String without the lead/trailing strings
|
||||
*/
|
||||
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
|
||||
* @param l Leading string to remove
|
||||
* @param t Trailing string to remove
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes ( and ) from the beginning and end of a string
|
||||
* @param s String to remove from
|
||||
* @return String without the ( or )
|
||||
*/
|
||||
public static String removePara(String s)
|
||||
{
|
||||
return remove(s,"(",")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes ( and ) from the beginning and end of all tokens
|
||||
* @return String without the ( or )
|
||||
*/
|
||||
public void removePara()
|
||||
{
|
||||
remove("(",")");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes [ and ] from the beginning and end of a string
|
||||
* @param s String to remove from
|
||||
* @return String without the [ or ]
|
||||
*/
|
||||
public static String removeBox(String s)
|
||||
{
|
||||
return remove(s,"[","]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes [ and ] from the beginning and end of all tokens
|
||||
* @return String without the [ or ]
|
||||
*/
|
||||
public void removeBox()
|
||||
{
|
||||
remove("[","]");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes < and > from the beginning and end of a string
|
||||
* @param s String to remove from
|
||||
* @return String without the < or >
|
||||
*/
|
||||
public static String removeAngle(String s)
|
||||
{
|
||||
return remove(s,"<",">");
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes < and > from the beginning and end of all tokens
|
||||
* @return String without the < or >
|
||||
*/
|
||||
public void removeAngle()
|
||||
{
|
||||
remove("<",">");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user