Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/postgresql/Driver.java


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