View Javadoc
1   /*
2    * $Source$
3    * $Revision$
4    *
5    * Copyright (C) 2000 David Warnock
6    * 
7    * Part of Melati (http://melati.org), a framework for the rapid
8    * development of clean, maintainable web applications.
9    *
10   * Melati is free software; Permission is granted to copy, distribute
11   * and/or modify this software under the terms either:
12   *
13   * a) the GNU General Public License as published by the Free Software
14   *    Foundation; either version 2 of the License, or (at your option)
15   *    any later version,
16   *
17   *    or
18   *
19   * b) any version of the Melati Software License, as published
20   *    at http://melati.org
21   *
22   * You should have received a copy of the GNU General Public License and
23   * the Melati Software License along with this program;
24   * if not, write to the Free Software Foundation, Inc.,
25   * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA to obtain the
26   * GNU General Public License and visit http://melati.org to obtain the
27   * Melati Software License.
28   *
29   * Feel free to contact the Developers of Melati (http://melati.org),
30   * if you would like to work out a different arrangement than the options
31   * outlined here.  It is our intention to allow Melati to be used by as
32   * wide an audience as possible.
33   *
34   * This program is distributed in the hope that it will be useful,
35   * but WITHOUT ANY WARRANTY; without even the implied warranty of
36   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37   * GNU General Public License for more details.
38   *
39   * Contact details for copyright holder:
40   *
41   *     David Warnock (david@sundayta.co.uk)
42   *     Sundayta Ltd
43   *     International House, 174 Three Bridges Road, Crawley,
44   *     West Sussex RH10 1LE, UK
45   *
46   */
47  
48  package org.melati.poem.dbms;
49  
50  import java.sql.Connection;
51  import java.sql.PreparedStatement;
52  import java.sql.ResultSet;
53  import java.sql.SQLException;
54  
55  import org.melati.poem.Column;
56  import org.melati.poem.PoemType;
57  import org.melati.poem.SQLPoemException;
58  import org.melati.poem.SQLPoemType;
59  import org.melati.poem.SQLType;
60  import org.melati.poem.Table;
61  
62  /**
63   * A Database Management System.
64   */
65  public interface Dbms {
66    
67    /**
68     * Used in tests to allow multiple dbmsen to be loaded and unloaded.
69     */
70    void unloadDriver();
71    
72    /**
73     * Return a connection.
74     * @param url the jdbc URL
75     * @param user the user to connect as, may be null
76     * @param password the password for user, may be null
77     * @return the connection
78     * @throws ConnectionFailurePoemException is we cannot connect
79     */
80    Connection getConnection(String url, String user, String password)
81        throws ConnectionFailurePoemException;
82  
83    /**
84     * The db schema name to use, if any.
85     * This is typically the JDBC connection URL User string.
86     * 
87     * @return the schema to use or null if not required
88     */
89    String getSchema();
90    
91    /**
92     * A no-op for all but hsqldb, where the db needs to be shutdown 
93     * when the servlet container or jvm is destroyed.   
94     */
95    void shutdown(Connection connection) throws SQLException;
96    
97    /**
98     * Accommodate different quoting strategies.
99     * 
100    * @param name the unquoted name
101    * @return the name quoted (or not) appropriate for this Dbms
102    */
103   String getQuotedName(String name);
104 
105   /**
106    * Accommodate different quoting strategies for values.
107    * 
108    * @param sqlType the SQLType of the value
109    * @param value the value
110    * @return a String quoted appropriately
111    */
112   String getQuotedValue(SQLType<?> sqlType, String value);
113   
114   /**
115    * Some DBMSen (HSQLDB) use canonical uppercased names in the metadata but not 
116    * in normal use. 
117    * 
118    * see org.melati.poem.Table#unifyWithDB
119    * @param name entity name such as <tt>tableinfo</tt>
120    * @return the (un)quoted name
121    */
122   String getJdbcMetadataName(String name);
123 
124   /**
125    * Accommodate casting in placeholders.
126    * 
127    * @param type the PoemType
128    * @return the place holder
129    * @see Postgresql
130    */
131   String preparedStatementPlaceholder(PoemType<?> type);
132 
133   /**
134    * 
135    * @return The appropriate SQL string to create a table 
136    */
137   String createTableSql(Table<?> table);
138   
139   /**
140    * Allow Hsqldb to have a different create table syntax.
141    * Should have trailing space if not empty String
142    */
143   String createTableTypeQualifierSql(Table<?> table);
144   
145   /**
146    * Accomodate MySQL table creation options.
147    * @return DMBS specific table creation options or empty String
148    */
149   String createTableOptionsSql();
150 
151   /**
152    * @return SQL to be run after creation or null
153    */
154   String tableInitialisationSql(Table<?> table);
155      
156  /**
157   * Retrieve a SQL type keyword used by the DBMS 
158   * for the given Melati type name.
159   *
160   * Override this in non-Ansi standard dbms to handle 
161   * variants.
162   *
163   * @param sqlTypeName the Melati internal type name
164   * @return this dbms specific type keyword
165   */
166   String getSqlDefinition(String sqlTypeName);
167 
168   /**
169    * Accommodate String / Text distinction.
170    * 
171    * @param size the string length (-1 means no limit)
172    * @return the SQL definition for a string of this size 
173    * @throws SQLException
174    */
175   String getStringSqlDefinition(int size) throws SQLException;
176 
177   /**
178    * Accommodate Long / Bigint deviants.
179    * @return the keyword to use.
180    */
181   String getLongSqlDefinition();
182 
183   /**
184    * Accommodate different true and false values. 
185    * 
186    * @return the DBMS specific truth and false values 
187    */
188   String sqlBooleanValueOfRaw(Object raw);
189   
190   /**
191    * Accommodate different treatment of different sized binary data.
192    * 
193    * @param size how big the field is
194    * @return the keyword to use
195    * @throws SQLException 
196    */
197   String getBinarySqlDefinition(int size) throws SQLException;
198   
199   /**
200    * Accommodate differing Fixed Point notations.
201    * 
202    * @param scale the number of places to right of decimal point
203    * @param precision how many digits in total
204    * @return the keywords to use
205    * @throws SQLException potentially
206    */
207   String getFixedPtSqlDefinition(int scale, int precision) throws SQLException;
208 
209   /**
210    * Enable one PoemType to represent another, 
211    * for example a <tt>bit</tt> to represent a <tt>boolean</tt>.
212    * 
213    * @param storage the container
214    * @param other the type to store
215    * @return the PoemType to use
216    */
217   <S,O>PoemType<O> canRepresent(PoemType<S> storage, PoemType<O> other);
218 
219   /**
220    * The simplest POEM type corresponding to a JDBC description from the
221    * database.
222    * 
223    * @param rs the JDBC metadata
224    * @return the PoemType to use 
225    * @throws SQLException potentially
226    */
227   SQLPoemType<?> defaultPoemTypeOfColumnMetaData(ResultSet rs)
228       throws SQLException;
229 
230   /**
231    * Whether this DBMS can drop columns.
232    * 
233    * @return true if we can
234    */
235   boolean canDropColumns(); 
236   
237   /**
238    * Whether this DBMS can store binary data.
239    * 
240    * @return true if we can
241    */
242   boolean canStoreBlobs();
243 
244   /**
245    * An exception appropriate for expressing what really went wrong
246    * during a write to the db.  This gives the opportunity to
247    * try to interpret the <TT>getMessage</TT> text returned by
248    * the underlying driver, so that a more friendly error page
249    * can be put together for the user.
250    *
251    * Canonically, this is used to separate out "duplicate key"
252    * errors from more serious problems.
253    *
254    * @param table     The table on which the update was affected
255    * @param sql       The operation attempted, or possibly <TT>null</TT>
256    * @param insert    Whether the operation was an <TT>INSERT</TT> as
257    *                  opposed to an <TT>UPDATE</TT>
258    * @param e         The raw SQL exception: the routine is meant to
259    *                  try to interpret <TT>e.getMessage</TT> if it can
260    *
261    * @return an appropriate exception
262    * @see Postgresql#exceptionForUpdate
263    */
264   SQLPoemException exceptionForUpdate(Table<?> table, String sql, boolean insert,
265                                       SQLException e);
266 
267   /**
268    * Version of previous method for <TT>PreparedStatement</TT>s.  By default
269    * (in the <TT>AnsiStandard</TT> implementation of <TT>Dbms</TT>) this simply
270    * invokes <TT>PreparedStatement.toString()</TT> and calls the
271    * <TT>String</TT> version.
272    *
273    * @param table     The table on which the update was affected
274    * @param ps        The operation attempted, or possibly <TT>null</TT>
275    * @param insert    Whether the operation was an <TT>INSERT</TT> as
276    *                  opposed to an <TT>UPDATE</TT>
277    * @param e         The raw SQL exception: the routine is meant to
278    *                  try to interpret <TT>e.getMessage</TT> if it can
279    * @return an appropriate exception
280    * @see AnsiStandard#exceptionForUpdate(org.melati.poem.Table, java.lang.String, 
281    *                             boolean, java.sql.SQLException)
282    */
283 
284   SQLPoemException exceptionForUpdate(Table<?> table, PreparedStatement ps,
285                                       boolean insert, SQLException e);
286 
287   /**
288    * Translate special names to non special ones.
289    * 
290    * @param name the field or table name
291    * @return the name translated if necessary
292    */
293   String unreservedName(String name);
294   
295   /**
296    * Reverse the mapping in <tt>unreservedName</tt>.
297    * 
298    * @param name an SQL name
299    * @return the corresponding name to use within Melati
300    */
301   String melatiName(String name);
302 
303   /**
304    * Accommodate DBMS which require a length for BLOBS.
305    * 
306    * @param column the POEM Column we are dealing with
307    * @return SQL length string
308    */
309   String getIndexLength(Column<?> column);
310 
311   /**
312    * Whether a <tt>Column</tt> can have an SQL index applied to it.
313    * 
314    * @param column the POEM Column we are dealing with
315    * @return true if it can, false otherwise.
316    */
317   boolean canBeIndexed(Column<?> column);
318 
319   /**
320    * SQL string to get a <tt>Capability</tt>.
321    * 
322    * @param userTroid the troid of the User to use in the query
323    * @param capabilityExpr the capability troid we need
324    * @return the SQL query to use
325    */
326   String givesCapabilitySQL(Integer userTroid, String capabilityExpr);
327 
328   /**
329    * Accommodate the variety of ways of ignoring case.
330    * 
331    * @param term1 the term to find in 
332    * @param term2 the quoted term to find 
333    * @return the SQL query to use
334    */
335   String caseInsensitiveRegExpSQL(String term1, String term2);
336 
337   /**
338    * A string to represent this DBMS.
339    * 
340    * @return the class name.
341    */
342   String toString();
343 
344   /**
345    * If Foreign key definitions are part of field definitions,
346    * otherwise blank (silently unsupported).
347    *  
348    * @param tableName the table that this column is in, unquoted
349    * @param fieldName often the name of the foreign table, unquoted
350    * @param targetTableName the table that this is a foreign key into, unquoted
351    * @param targetTableFieldName name of the primary key field of the foreign 
352    * table, often id, unquoted
353    * @param fixName name of the IntegrityFix 
354    * 
355    * @return The definition string
356    */
357   String getForeignKeyDefinition(String tableName, String fieldName, 
358       String targetTableName, String targetTableFieldName, String fixName);
359 
360   /**
361    * Return the PRIMARY KEY definition string for this dbms. 
362    *
363    * @param fieldName the table Troid column, often <code>id</code>, unquoted
364    * 
365    * @return The definition string
366    */
367   String getPrimaryKeyDefinition(String fieldName);
368 
369   /**
370    * Return the SQL snippet to alter a column to not nullable.
371    * @param tableName
372    * @param column
373    * @return SQL snippet to set a column not nullable
374    */
375   String alterColumnNotNullableSQL(String tableName, Column<?> column);
376 
377   /**
378    * @param column the target to add a remark to
379    * @param comment the remark to add
380    * @return an update SQL command or null 
381    */
382   String alterColumnAddCommentSQL(Column<?> column, String comment);
383   
384   /**
385    * @param table the target to add a remark to
386    * @param comment the remark to add
387    * @return an update SQL command or null 
388    */
389   String alterTableAddCommentSQL(Table<?> table, String comment);
390   
391   /**
392    * Accommodate different limiting syntax.
393    * 
394    * @param querySelection main body of query
395    * @param limit number to limit to
396    * @return limited query
397    */
398   String selectLimit(String querySelection, int limit);
399 
400   /**
401    * Accommodate lack of boolean types in underlying DBMS.
402    * @param booleanColumn the column which should be a boolean
403    * @return an expression that evaluates to True ie the column name or column name = 1
404    */
405   String booleanTrueExpression(Column<Boolean> booleanColumn);
406 
407   /**
408    * Used to set a not null value when 
409    * creating a non nullable column.
410    * @param type the type name
411    * @return a String suitable for substitution in UPDATE table SET field = ?
412    */
413   String getSqlDefaultValue(SQLType<?> type);
414 
415 }