Fastpath.java
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:9k
源码类别:

mpeg/mp3

开发平台:

C/C++

  1. package postgresql.fastpath;
  2. import java.io.*;
  3. import java.lang.*;
  4. import java.net.*;
  5. import java.util.*;
  6. import java.sql.*;
  7. import postgresql.util.*;
  8. /**
  9.  * This class implements the Fastpath api.
  10.  *
  11.  * <p>This is a means of executing functions imbeded in the postgresql backend
  12.  * from within a java application.
  13.  *
  14.  * <p>It is based around the file src/interfaces/libpq/fe-exec.c
  15.  *
  16.  *
  17.  * <p><b>Implementation notes:</b>
  18.  *
  19.  * <p><b><em>Network protocol:</em></b>
  20.  *
  21.  * <p>The code within the backend reads integers in reverse.
  22.  *
  23.  * <p>There is work in progress to convert all of the protocol to
  24.  * network order but it may not be there for v6.3
  25.  *
  26.  * <p>When fastpath switches, simply replace SendIntegerReverse() with
  27.  * SendInteger()
  28.  *
  29.  * @see postgresql.FastpathFastpathArg
  30.  * @see postgresql.LargeObject
  31.  */
  32. public class Fastpath
  33. {
  34.   // This maps the functions names to their id's (possible unique just
  35.   // to a connection).
  36.   protected Hashtable func = new Hashtable();
  37.   
  38.   protected postgresql.Connection conn; // our connection
  39.   protected postgresql.PG_Stream stream; // the network stream
  40.   
  41.   /**
  42.    * Initialises the fastpath system
  43.    *
  44.    * <p><b>Important Notice</b>
  45.    * <br>This is called from postgresql.Connection, and should not be called
  46.    * from client code.
  47.    *
  48.    * @param conn postgresql.Connection to attach to
  49.    * @param stream The network stream to the backend
  50.    */
  51.   public Fastpath(postgresql.Connection conn,postgresql.PG_Stream stream)
  52.   {
  53.     this.conn=conn;
  54.     this.stream=stream;
  55.     DriverManager.println("Fastpath initialised");
  56.   }
  57.   
  58.   /**
  59.    * Send a function call to the PostgreSQL backend
  60.    *
  61.    * @param fnid Function id
  62.    * @param resulttype True if the result is an integer, false for other results
  63.    * @param args FastpathArguments to pass to fastpath
  64.    * @return null if no data, Integer if an integer result, or byte[] otherwise
  65.    * @exception SQLException if a database-access error occurs.
  66.    */
  67.   public Object fastpath(int fnid,boolean resulttype,FastpathArg[] args) throws SQLException
  68.   {
  69.     // added Oct 7 1998 to give us thread safety
  70.     synchronized(stream) {
  71.       
  72.     // send the function call
  73.     try {
  74.       // 70 is 'F' in ASCII. Note: don't use SendChar() here as it adds padding
  75.       // that confuses the backend. The 0 terminates the command line.
  76.       stream.SendInteger(70,1);
  77.       stream.SendInteger(0,1);
  78.       
  79.       //stream.SendIntegerReverse(fnid,4);
  80.       //stream.SendIntegerReverse(args.length,4);
  81.       stream.SendInteger(fnid,4);
  82.       stream.SendInteger(args.length,4);
  83.       
  84.       for(int i=0;i<args.length;i++)
  85. args[i].send(stream);
  86.       
  87.       // This is needed, otherwise data can be lost
  88.       stream.flush();
  89.       
  90.     } catch(IOException ioe) {
  91.       throw new SQLException("Failed to send fastpath call "+fnid+"n"+ioe);
  92.     }
  93.     
  94.     // Now handle the result
  95.     
  96.     // We should get 'V' on sucess or 'E' on error. Anything else is treated
  97.     // as an error.
  98.     //int in = stream.ReceiveChar();
  99.     //DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
  100.     //if(in!='V') {
  101.     //if(in=='E')
  102.     //throw new SQLException(stream.ReceiveString(4096));
  103.     //throw new SQLException("Fastpath: expected 'V' from backend, got "+((char)in));
  104.     //}
  105.     
  106.     // Now loop, reading the results
  107.     Object result = null; // our result
  108.     while(true) {
  109.       int in = stream.ReceiveChar();
  110.       DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
  111.       switch(in)
  112. {
  113. case 'V':
  114.   break;
  115.   
  116.   //------------------------------
  117.   // Function returned properly
  118.   //
  119. case 'G':
  120.   int sz = stream.ReceiveIntegerR(4);
  121.   DriverManager.println("G: size="+sz);  //debug
  122.   
  123.   // Return an Integer if
  124.   if(resulttype)
  125.     result = new Integer(stream.ReceiveIntegerR(sz));
  126.   else {
  127.     byte buf[] = new byte[sz];
  128.     stream.Receive(buf,0,sz);
  129.     result = buf;
  130.   }
  131.   break;
  132.   
  133.   //------------------------------
  134.   // Error message returned
  135. case 'E':
  136.   throw new SQLException("Fastpath: "+stream.ReceiveString(4096));
  137.   
  138.   //------------------------------
  139.   // Notice from backend
  140. case 'N':
  141.   conn.addWarning(stream.ReceiveString(4096));
  142.   break;
  143.   
  144.   //------------------------------
  145.   // End of results
  146.   //
  147.   // Here we simply return res, which would contain the result
  148.   // processed earlier. If no result, this already contains null
  149. case '0':
  150.   DriverManager.println("returning "+result);
  151.   return result;
  152.   
  153. default:
  154.   throw new SQLException("Fastpath: protocol error. Got '"+((char)in)+"'");
  155. }
  156.     }
  157.     }
  158.   }
  159.   
  160.   /**
  161.    * Send a function call to the PostgreSQL backend by name.
  162.    *
  163.    * Note: the mapping for the procedure name to function id needs to exist,
  164.    * usually to an earlier call to addfunction().
  165.    *
  166.    * This is the prefered method to call, as function id's can/may change
  167.    * between versions of the backend.
  168.    *
  169.    * For an example of how this works, refer to postgresql.LargeObject
  170.    *
  171.    * @param name Function name
  172.    * @param resulttype True if the result is an integer, false for other
  173.    * results
  174.    * @param args FastpathArguments to pass to fastpath
  175.    * @return null if no data, Integer if an integer result, or byte[] otherwise
  176.    * @exception SQLException if name is unknown or if a database-access error
  177.    * occurs.
  178.    * @see postgresql.LargeObject
  179.    */
  180.   public Object fastpath(String name,boolean resulttype,FastpathArg[] args) throws SQLException
  181.   {
  182.     DriverManager.println("Fastpath: calling "+name);
  183.     return fastpath(getID(name),resulttype,args);
  184.   }
  185.   
  186.   /**
  187.    * This convenience method assumes that the return value is an Integer
  188.    * @param name Function name
  189.    * @param args Function arguments
  190.    * @return integer result
  191.    * @exception SQLException if a database-access error occurs or no result
  192.    */
  193.   public int getInteger(String name,FastpathArg[] args) throws SQLException
  194.   {
  195.     Integer i = (Integer)fastpath(name,true,args);
  196.     if(i==null)
  197.       throw new SQLException("Fastpath:"+name+": no result returned, expected integer");
  198.     return i.intValue();
  199.   }
  200.   
  201.   /**
  202.    * This convenience method assumes that the return value is an Integer
  203.    * @param name Function name
  204.    * @param args Function arguments
  205.    * @return byte[] array containing result
  206.    * @exception SQLException if a database-access error occurs or no result
  207.    */
  208.   public byte[] getData(String name,FastpathArg[] args) throws SQLException
  209.   {
  210.     return (byte[])fastpath(name,false,args);
  211.   }
  212.   
  213.   /**
  214.    * This adds a function to our lookup table.
  215.    *
  216.    * <p>User code should use the addFunctions method, which is based upon a
  217.    * query, rather than hard coding the oid. The oid for a function is not
  218.    * guaranteed to remain static, even on different servers of the same
  219.    * version.
  220.    *
  221.    * @param name Function name
  222.    * @param fnid Function id
  223.    */
  224.   public void addFunction(String name,int fnid)
  225.   {
  226.     func.put(name,new Integer(fnid));
  227.   }
  228.   
  229.   /**
  230.    * This takes a ResultSet containing two columns. Column 1 contains the
  231.    * function name, Column 2 the oid.
  232.    *
  233.    * <p>It reads the entire ResultSet, loading the values into the function
  234.    * table.
  235.    *
  236.    * <p><b>REMEMBER</b> to close() the resultset after calling this!!
  237.    *
  238.    * <p><b><em>Implementation note about function name lookups:</em></b>
  239.    *
  240.    * <p>PostgreSQL stores the function id's and their corresponding names in
  241.    * the pg_proc table. To speed things up locally, instead of querying each
  242.    * function from that table when required, a Hashtable is used. Also, only
  243.    * the function's required are entered into this table, keeping connection
  244.    * times as fast as possible.
  245.    *
  246.    * <p>The postgresql.LargeObject class performs a query upon it's startup,
  247.    * and passes the returned ResultSet to the addFunctions() method here.
  248.    *
  249.    * <p>Once this has been done, the LargeObject api refers to the functions by
  250.    * name.
  251.    *
  252.    * <p>Dont think that manually converting them to the oid's will work. Ok,
  253.    * they will for now, but they can change during development (there was some
  254.    * discussion about this for V7.0), so this is implemented to prevent any
  255.    * unwarranted headaches in the future.
  256.    *
  257.    * @param rs ResultSet
  258.    * @exception SQLException if a database-access error occurs.
  259.    * @see postgresql.LargeObjectManager
  260.    */
  261.   public void addFunctions(ResultSet rs) throws SQLException
  262.   {
  263.     while(rs.next()) {
  264.       func.put(rs.getString(1),new Integer(rs.getInt(2)));
  265.     }
  266.   }
  267.   
  268.   /**
  269.    * This returns the function id associated by its name
  270.    *
  271.    * <p>If addFunction() or addFunctions() have not been called for this name,
  272.    * then an SQLException is thrown.
  273.    *
  274.    * @param name Function name to lookup
  275.    * @return Function ID for fastpath call
  276.    * @exception SQLException is function is unknown.
  277.    */
  278.   public int getID(String name) throws SQLException
  279.   {
  280.     Integer id = (Integer)func.get(name);
  281.     
  282.     // may be we could add a lookup to the database here, and store the result
  283.     // in our lookup table, throwing the exception if that fails.
  284.     // We must, however, ensure that if we do, any existing ResultSet is
  285.     // unaffected, otherwise we could break user code.
  286.     //
  287.     // so, until we know we can do this (needs testing, on the TODO list)
  288.     // for now, we throw the exception and do no lookups.
  289.     if(id==null)
  290.       throw new SQLException("Fastpath: function "+name+" is unknown");
  291.     
  292.     return id.intValue();
  293.   }
  294. }