package postgresql.fastpath; import java.io.*; import java.lang.*; import java.net.*; import java.util.*; import java.sql.*; import postgresql.util.*; // Important: There are a lot of debug code commented out. Please do not // delete these. /** * This class implements the Fastpath api. * *
This is a means of executing functions imbeded in the postgresql backend * from within a java application. * *
It is based around the file src/interfaces/libpq/fe-exec.c * * *
Implementation notes: * *
Network protocol: * *
The code within the backend reads integers in reverse. * *
There is work in progress to convert all of the protocol to * network order but it may not be there for v6.3 * *
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 * *
Important Notice
   *  It reads the entire ResultSet, loading the values into the function
   * table.
   *
   *  REMEMBER to close() the resultset after calling this!!
   *
   *  Implementation note about function name lookups:
   *
   *  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.
   *
   *  The postgresql.LargeObject class performs a query upon it's startup,
   * and passes the returned ResultSet to the addFunctions() method here.
   *
   *  Once this has been done, the LargeObject api refers to the functions by
   * name.
   *
   *  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
   *
   *  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 PSQLException("postgresql.fp.unknown",name);
    
    return id.intValue();
  }
}
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
  {
    // added Oct 7 1998 to give us thread safety
    synchronized(stream) {
      
    // 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);
      stream.SendInteger(fnid,4);
      stream.SendInteger(args.length,4);
      
      for(int i=0;i