Driver.java
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:11k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. package postgresql;
  2. import java.sql.*;
  3. import java.util.*;
  4. import postgresql.util.PSQLException;
  5. /**
  6.  * The Java SQL framework allows for multiple database drivers.  Each
  7.  * driver should supply a class that implements the Driver interface
  8.  *
  9.  * <p>The DriverManager will try to load as many drivers as it can find and
  10.  * then for any given connection request, it will ask each driver in turn
  11.  * to try to connect to the target URL.
  12.  *
  13.  * <p>It is strongly recommended that each Driver class should be small and
  14.  * standalone so that the Driver class can be loaded and queried without
  15.  * bringing in vast quantities of supporting code.
  16.  *
  17.  * <p>When a Driver class is loaded, it should create an instance of itself
  18.  * and register it with the DriverManager.  This means that a user can load
  19.  * and register a driver by doing Class.forName("foo.bah.Driver")
  20.  *
  21.  * @see postgresql.Connection
  22.  * @see java.sql.Driver
  23.  */
  24. public class Driver implements java.sql.Driver 
  25. {
  26.   // These should be in sync with the backend that the driver was
  27.   // distributed with
  28.   static final int MAJORVERSION = 6;
  29.   static final int MINORVERSION = 5;
  30.     
  31.   // Cache the version of the JDK in use
  32.   static String connectClass;
  33.     
  34.   static 
  35.   {
  36.     try {
  37.       // moved the registerDriver from the constructor to here
  38.       // because some clients call the driver themselves (I know, as
  39.       // my early jdbc work did - and that was based on other examples).
  40.       // Placing it here, means that the driver is registered once only.
  41.       java.sql.DriverManager.registerDriver(new Driver());
  42.     } catch (SQLException e) {
  43.       e.printStackTrace();
  44.     }
  45.   }
  46.   
  47.   /**
  48.    * Construct a new driver and register it with DriverManager
  49.    *
  50.    * @exception SQLException for who knows what!
  51.    */
  52.   public Driver() throws SQLException
  53.   {
  54.       // Set the connectClass variable so that future calls will handle the correct
  55.       // base class
  56.       if(System.getProperty("java.version").startsWith("1.1")) {
  57.   connectClass = "postgresql.jdbc1.Connection";
  58.       } else {
  59.   connectClass = "postgresql.jdbc2.Connection";
  60.       }
  61.   }
  62.   
  63.   /**
  64.    * Try to make a database connection to the given URL.  The driver
  65.    * should return "null" if it realizes it is the wrong kind of
  66.    * driver to connect to the given URL.  This will be common, as
  67.    * when the JDBC driverManager is asked to connect to a given URL,
  68.    * it passes the URL to each loaded driver in turn.
  69.    *
  70.    * <p>The driver should raise an SQLException if it is the right driver
  71.    * to connect to the given URL, but has trouble connecting to the
  72.    * database.
  73.    *
  74.    * <p>The java.util.Properties argument can be used to pass arbitrary
  75.    * string tag/value pairs as connection arguments.  Normally, at least
  76.    * "user" and "password" properties should be included in the 
  77.    * properties.
  78.    *
  79.    * Our protocol takes the forms:
  80.    * <PRE>
  81.    * jdbc:postgresql://host:port/database?param1=val1&...
  82.    * </PRE>
  83.    *
  84.    * @param url the URL of the database to connect to
  85.    * @param info a list of arbitrary tag/value pairs as connection
  86.    * arguments
  87.    * @return a connection to the URL or null if it isnt us
  88.    * @exception SQLException if a database access error occurs
  89.    * @see java.sql.Driver#connect
  90.    */
  91.   public java.sql.Connection connect(String url, Properties info) throws SQLException
  92.   {
  93.     if((props = parseURL(url,info))==null)
  94.       return null;
  95.     
  96.     DriverManager.println("Using "+connectClass);
  97.     
  98.     try {
  99. postgresql.Connection con = (postgresql.Connection)(Class.forName(connectClass).newInstance());
  100. con.openConnection (host(), port(), props, database(), url, this);
  101. return (java.sql.Connection)con;
  102.     } catch(ClassNotFoundException ex) {
  103. throw new PSQLException("postgresql.jvm.version",ex);
  104.     } catch(PSQLException ex1) {
  105. // re-throw the exception, otherwise it will be caught next, and a
  106. // postgresql.unusual error will be returned instead.
  107. throw ex1;
  108.     } catch(Exception ex2) {
  109. throw new PSQLException("postgresql.unusual",ex2);
  110.     }
  111.   }
  112.   
  113.   /**
  114.    * Returns true if the driver thinks it can open a connection to the
  115.    * given URL.  Typically, drivers will return true if they understand
  116.    * the subprotocol specified in the URL and false if they don't.  Our
  117.    * protocols start with jdbc:postgresql:
  118.    *
  119.    * @see java.sql.Driver#acceptsURL
  120.    * @param url the URL of the driver
  121.    * @return true if this driver accepts the given URL
  122.    * @exception SQLException if a database-access error occurs
  123.    *  (Dont know why it would *shrug*)
  124.    */
  125.   public boolean acceptsURL(String url) throws SQLException
  126.   {
  127.     if(parseURL(url,null)==null)
  128.       return false;
  129.     return true;
  130.   }
  131.   
  132.   /**
  133.    * The getPropertyInfo method is intended to allow a generic GUI
  134.    * tool to discover what properties it should prompt a human for
  135.    * in order to get enough information to connect to a database.
  136.    *
  137.    * <p>Note that depending on the values the human has supplied so
  138.    * far, additional values may become necessary, so it may be necessary
  139.    * to iterate through several calls to getPropertyInfo
  140.    *
  141.    * @param url the Url of the database to connect to
  142.    * @param info a proposed list of tag/value pairs that will be sent on
  143.    *  connect open.
  144.    * @return An array of DriverPropertyInfo objects describing
  145.    *  possible properties.  This array may be an empty array if
  146.    * no properties are required
  147.    * @exception SQLException if a database-access error occurs
  148.    * @see java.sql.Driver#getPropertyInfo
  149.    */
  150.   public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException
  151.   {
  152.     Properties p = parseURL(url,info);
  153.     
  154.     // naughty, but its best for speed. If anyone adds a property here, then
  155.     // this _MUST_ be increased to accomodate them.
  156.     DriverPropertyInfo d,dpi[] = new DriverPropertyInfo[0];
  157.     //int i=0;
  158.     
  159.     //dpi[i++] = d = new DriverPropertyInfo("auth",p.getProperty("auth","default"));
  160.     //d.description = "determines if password authentication is used";
  161.     //d.choices = new String[4];
  162.     //d.choices[0]="default"; // Get value from postgresql.auth property, defaults to trust
  163.     //d.choices[1]="trust"; // No password authentication
  164.     //d.choices[2]="password"; // Password authentication
  165.     //d.choices[3]="ident"; // Ident (RFC 1413) protocol
  166.     
  167.     return dpi;
  168.   }
  169.   
  170.   /**
  171.    * Gets the drivers major version number
  172.    *
  173.    * @return the drivers major version number
  174.    */
  175.   public int getMajorVersion()
  176.   {
  177.     return MAJORVERSION;
  178.   }
  179.   
  180.   /**
  181.    * Get the drivers minor version number
  182.    *
  183.    * @return the drivers minor version number
  184.    */
  185.   public int getMinorVersion()
  186.   {
  187.     return MINORVERSION;
  188.   }
  189.   
  190.   /**
  191.    * Report whether the driver is a genuine JDBC compliant driver.  A
  192.    * driver may only report "true" here if it passes the JDBC compliance
  193.    * tests, otherwise it is required to return false.  JDBC compliance
  194.    * requires full support for the JDBC API and full support for SQL 92
  195.    * Entry Level.  
  196.    *
  197.    * <p>For PostgreSQL, this is not yet possible, as we are not SQL92
  198.    * compliant (yet).
  199.    */
  200.   public boolean jdbcCompliant()
  201.   {
  202.     return false;
  203.   }
  204.   
  205.   private Properties props;
  206.   
  207.   static private String[] protocols = { "jdbc","postgresql" };
  208.   
  209.   /**
  210.    * Constructs a new DriverURL, splitting the specified URL into its
  211.    * component parts
  212.    * @param url JDBC URL to parse
  213.    * @param defaults Default properties
  214.    * @return Properties with elements added from the url
  215.    * @exception SQLException
  216.    */
  217.   Properties parseURL(String url,Properties defaults) throws SQLException
  218.   {
  219.     int state = -1;
  220.     Properties urlProps = new Properties(defaults);
  221.     String key = new String();
  222.     String value = new String();
  223.     
  224.     StringTokenizer st = new StringTokenizer(url, ":/;=&?", true);
  225.     for (int count = 0; (st.hasMoreTokens()); count++) {
  226.       String token = st.nextToken();
  227.       
  228.       // PM June 29 1997
  229.       // Added this, to help me understand how this works.
  230.       // Unless you want each token to be processed, leave this commented out
  231.       // but don't delete it.
  232.       //DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'");
  233.       
  234.       // PM Aug 2 1997 - Modified to allow multiple backends
  235.       if (count <= 3) {
  236. if ((count % 2) == 1 && token.equals(":"))
  237.   ;
  238. else if((count % 2) == 0) {
  239.   boolean found=(count==0)?true:false;
  240.   for(int tmp=0;tmp<protocols.length;tmp++) {
  241.     if(token.equals(protocols[tmp])) {
  242.       // PM June 29 1997 Added this property to enable the driver
  243.       // to handle multiple backend protocols.
  244.       if(count == 2 && tmp > 0) {
  245. urlProps.put("Protocol",token);
  246. found=true;
  247.       }
  248.     }
  249.   }
  250.   
  251.   if(found == false)
  252.     return null;
  253. } else return null;
  254.       }
  255.       else if (count > 3) {
  256. if (count == 4 && token.equals("/")) state = 0;
  257. else if (count == 4) {
  258.   urlProps.put("PGDBNAME", token);
  259.   state = -2;
  260. }
  261. else if (count == 5 && state == 0 && token.equals("/"))
  262.   state = 1;
  263. else if (count == 5 && state == 0)
  264.   return null;
  265. else if (count == 6 && state == 1)
  266.   urlProps.put("PGHOST", token);
  267. else if (count == 7 && token.equals(":")) state = 2;
  268. else if (count == 8 && state == 2) {
  269.   try {
  270.     Integer portNumber = Integer.decode(token);
  271.     urlProps.put("PGPORT", portNumber.toString());
  272.   } catch (Exception e) {
  273.     return null;
  274.   }
  275. }
  276. else if ((count == 7 || count == 9) &&
  277.  (state == 1 || state == 2) && token.equals("/"))
  278.   state = -1;
  279. else if (state == -1) {
  280.   urlProps.put("PGDBNAME", token);
  281.   state = -2;
  282. }
  283. else if (state <= -2 && (count % 2) == 1) {
  284.   // PM Aug 2 1997 - added tests for ? and &
  285.   if (token.equals(";") || token.equals("?") || token.equals("&") ) state = -3;
  286.   else if (token.equals("=")) state = -5;
  287. }
  288. else if (state <= -2 && (count % 2) == 0) {
  289.   if (state == -3) key = token;
  290.   else if (state == -5) {
  291.     value = token;
  292.     //DriverManager.println("put("+key+","+value+")");
  293.     urlProps.put(key, value);
  294.     state = -2;
  295.   }
  296. }
  297.       }
  298.     }
  299.     
  300.     // PM June 29 1997
  301.     // This now outputs the properties only if we are logging
  302.     if(DriverManager.getLogStream() != null)
  303.       urlProps.list(DriverManager.getLogStream());
  304.     
  305.     return urlProps;
  306.     
  307.   }
  308.   
  309.   /**
  310.    * @return the hostname portion of the URL
  311.    */
  312.   public String host()
  313.   {
  314.     return props.getProperty("PGHOST","localhost");
  315.   }
  316.   
  317.   /**
  318.    * @return the port number portion of the URL or -1 if no port was specified
  319.    */
  320.   public int port()
  321.   {
  322.     return Integer.parseInt(props.getProperty("PGPORT","5432"));
  323.   }
  324.   
  325.   /**
  326.    * @return the database name of the URL
  327.    */
  328.   public String database()
  329.   {
  330.     return props.getProperty("PGDBNAME");
  331.   }
  332.   
  333.   /**
  334.    * @return the value of any property specified in the URL or properties
  335.    * passed to connect(), or null if not found.
  336.    */
  337.   public String property(String name)
  338.   {
  339.     return props.getProperty(name);
  340.   }
  341.     
  342.     /**
  343.      * This method was added in v6.5, and simply throws an SQLException
  344.      * for an unimplemented method. I decided to do it this way while
  345.      * implementing the JDBC2 extensions to JDBC, as it should help keep the
  346.      * overall driver size down.
  347.      */
  348.     public static SQLException notImplemented()
  349.     {
  350. return new PSQLException("postgresql.unimplemented");
  351.     }
  352. }