View Javadoc

1   package org.apache.torque.adapter;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.sql.Connection;
23  import java.sql.SQLException;
24  import java.sql.Timestamp;
25  import java.util.Date;
26  import java.util.Hashtable;
27  import java.util.Map;
28  
29  import org.apache.torque.TorqueException;
30  import org.apache.torque.util.Query;
31  import org.apache.torque.util.functions.Aggregate;
32  import org.apache.torque.util.functions.FunctionEnum;
33  
34  /***
35   * This class is the abstract base for any database adapter
36   * Support for new databases is added by subclassing this
37   * class and implementing its abstract methods, and by
38   * registering the new database adapter and its corresponding
39   * JDBC driver in the service configuration file.
40   *
41   * <p>The Torque database adapters exist to present a uniform
42   * interface to database access across all available databases.  Once
43   * the necessary adapters have been written and configured,
44   * transparent swapping of databases is theoretically supported with
45   * <i>zero code changes</i> and minimal configuration file
46   * modifications.
47   *
48   * <p>Torque uses the driver class name to find the right adapter.
49   * A JDBC driver corresponding to your adapter must be added to the properties
50   * file, using the fully-qualified class name of the driver. If no driver is
51   * specified for your database, <code>driver.default</code> is used.
52   *
53   * <pre>
54   * #### MySQL MM Driver
55   * database.default.driver=org.gjt.mm.mysql.Driver
56   * database.default.url=jdbc:mysql://localhost/DATABASENAME
57   * </pre>
58   *
59   * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
60   * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
61   * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
62   * @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
63   * @author <a href="mailto:greg.monroe@dukece.com">Greg Monroe</a>
64   * @version $Id: DB.java 393063 2006-04-10 20:59:16Z tfischer $
65   */
66  public abstract class AbstractDBAdapter implements DB
67  {
68      /*** 
69       * The default look up table for function classes.
70       */
71      private Map functionClasses = new Hashtable(10);
72      /*
73       * Initialize the functionClasses lookup table with SQL99 standard
74       * functions. Uses this method because DB implementations don't 
75       * currently call super() in their constructors and we want this
76       * to be set in all of them.
77       * 
78       * Override the values set here in the DB Specific adaptor's
79       * constructor.
80       */
81      {
82          functionClasses.put( FunctionEnum.AVG, Aggregate.Avg.class );
83          functionClasses.put( FunctionEnum.COUNT, Aggregate.Count.class );
84          functionClasses.put( FunctionEnum.MAX, Aggregate.Max.class );
85          functionClasses.put( FunctionEnum.MIN, Aggregate.Min.class );
86          functionClasses.put( FunctionEnum.SUM, Aggregate.Sum.class );
87      }
88      
89      /***
90       * Empty constructor.
91       */
92      protected AbstractDBAdapter()
93      {
94      }
95  
96      /***
97       * This method is used to ignore case.
98       *
99       * @param in The string to transform to upper case.
100      * @return The upper case string.
101      */
102     public abstract String toUpperCase(String in);
103 
104     /***
105      * Returns the character used to indicate the beginning and end of
106      * a piece of text used in a SQL statement (generally a single
107      * quote).
108      *
109      * @return The text delimeter.
110      */
111     public char getStringDelimiter()
112     {
113         return '\'';
114     }
115 
116     /***
117      * Returns the constant from the {@link
118      * org.apache.torque.adapter.IDMethod} interface denoting which
119      * type of primary key generation method this type of RDBMS uses.
120      *
121      * @return IDMethod constant
122      */
123     public abstract String getIDMethodType();
124 
125     /***
126      * Returns SQL used to get the most recently inserted primary key.
127      * Databases which have no support for this return
128      * <code>null</code>.
129      *
130      * @param obj Information used for key generation.
131      * @return The most recently inserted database key.
132      */
133     public abstract String getIDMethodSQL(Object obj);
134 
135     /***
136      * Locks the specified table.
137      *
138      * @param con The JDBC connection to use.
139      * @param table The name of the table to lock.
140      * @throws SQLException No Statement could be created or executed.
141      */
142     public abstract void lockTable(Connection con, String table)
143             throws SQLException;
144 
145     /***
146      * Unlocks the specified table.
147      *
148      * @param con The JDBC connection to use.
149      * @param table The name of the table to unlock.
150      * @throws SQLException No Statement could be created or executed.
151      */
152     public abstract void unlockTable(Connection con, String table)
153             throws SQLException;
154 
155     /***
156      * This method is used to ignore case.
157      *
158      * @param in The string whose case to ignore.
159      * @return The string in a case that can be ignored.
160      */
161     public abstract String ignoreCase(String in);
162 
163     /***
164      * This method is used to ignore case in an ORDER BY clause.
165      * Usually it is the same as ignoreCase, but some databases
166      * (Interbase for example) does not use the same SQL in ORDER BY
167      * and other clauses.
168      *
169      * @param in The string whose case to ignore.
170      * @return The string in a case that can be ignored.
171      */
172     public String ignoreCaseInOrderBy(String in)
173     {
174         return ignoreCase(in);
175     }
176 
177     /***
178      * This method is used to check whether the database natively
179      * supports limiting the size of the resultset.
180      *
181      * @return True if the database natively supports limiting the
182      * size of the resultset.
183      */
184     public boolean supportsNativeLimit()
185     {
186         return false;
187     }
188 
189     /***
190      * This method is used to check whether the database natively
191      * supports returning results starting at an offset position other
192      * than 0.
193      *
194      * @return True if the database natively supports returning
195      * results starting at an offset position other than 0.
196      */
197     public boolean supportsNativeOffset()
198     {
199         return false;
200     }
201 
202     /***
203      * This method is used to generate the database specific query
204      * extension to limit the number of record returned.
205      *
206      * @param query The query to modify
207      * @param offset the offset Value
208      * @param limit the limit Value
209      *
210      * @throws TorqueException if any error occurs when building the query
211      */
212     public void generateLimits(Query query, int offset, int limit)
213         throws TorqueException
214     {
215         if (supportsNativeLimit())
216         {
217             query.setLimit(String.valueOf(limit));
218         }
219     }
220 
221     /***
222     * This method is for the SqlExpression.quoteAndEscape rules.  The rule is,
223     * any string in a SqlExpression with a BACKSLASH will either be changed to
224     * "//" or left as "\".  SapDB does not need the escape character.
225     *
226     * @return true if the database needs to escape text in SqlExpressions.
227     */
228 
229     public boolean escapeText()
230     {
231         return true;
232     }
233 
234     /***
235      * This method is used to check whether the database supports
236      * limiting the size of the resultset.
237      *
238      * @return The limit style for the database.
239      * @deprecated This should not be exposed to the outside
240      */
241     public int getLimitStyle()
242     {
243         return LIMIT_STYLE_NONE;
244     }
245 
246     /***
247      * This method is used to format any date string.
248      * Database can use different default date formats.
249      *
250      * @param date the Date to format
251      * @return The proper date formatted String.
252      */
253     public String getDateString(Date date)
254     {
255         Timestamp ts = null;
256         if (date instanceof Timestamp)
257         {
258             ts = (Timestamp) date;
259         }
260         else
261         {
262             ts = new Timestamp(date.getTime());
263         }
264 
265         return ("{ts '" + ts + "'}");
266     }
267 
268     /***
269      * This method is used to format a boolean string.
270      *
271      * @param b the Boolean to format
272      * @return The proper date formatted String.
273      */
274     public String getBooleanString(Boolean b)
275     {
276         return (Boolean.TRUE.equals(b) ? "1" : "0");
277     }
278 
279     /***
280      * Whether ILIKE should be used for case insensitive like clauses.
281      *
282      * As most databases do not use ILIKE, this implementation returns false.
283      * This behaviour may be overwritten in subclasses.
284      *
285      * @return true if ilike should be used for case insensitive likes,
286      *         false if ignoreCase should be applied to the compared strings.
287      */
288     public boolean useIlike()
289     {
290         return false;
291     }
292 
293     /***
294      * Whether an escape clause in like should be used.
295      * Example : select * from AUTHOR where AUTHOR.NAME like '\_%' ESCAPE '\';
296      *
297      * As most databases do not need the escape clause, this implementation
298      * always returns <code>false</code>. This behaviour can be overwritten
299      * in subclasses.
300      *
301      * @return whether the escape clause should be appended or not.
302      */
303     public boolean useEscapeClauseForLike()
304     {
305         return false;
306     }
307 
308     /***
309      * Return the class which implements the SQLFunction interface for the
310      * specified function.
311      * 
312      * @param function The function to get the class for.
313      * @return The SQLFunction implementation for a function of this type that
314      *         will work with this type of DB. Null indicates a class was not
315      *         found. 
316      */
317     public Class getFunctionClass( FunctionEnum function ) 
318     {
319         return (Class) functionClasses.get( function );
320     }
321 
322 }