1 /*------------------------------------------------------------------------------
  2 Name:      DbMetaHelper.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 
  7 package org.xmlBlaster.contrib.db;
  8 
  9 import java.sql.Connection;
 10 import java.sql.DatabaseMetaData;
 11 import java.sql.ResultSet;
 12 import java.sql.SQLException;
 13 import java.util.TreeMap;
 14 
 15 /**
 16  * 
 17  * DbMetaHelper offers methods which take care of stuff specific to particular databases. For
 18  * example if a database stores table names in uppercase you don't need to bother about this
 19  * knowledge. You just pass the name of the table to the method getUnquotedIdentifier and you
 20  * get back the correct name (if uppercase it will be uppercase).
 21  * 
 22  * @author <a href="mailto:michele@laghi.eu">Michele Laghi</a>
 23  */
 24 public class DbMetaHelper {
 25 
 26    private final static int CASE_UNKNOWN = 0;
 27    private final static int CASE_MIXED = 1;
 28    private final static int CASE_UPPER = 2;
 29    private final static int CASE_LOWER = 3;
 30 
 31    private int caseSense = CASE_UNKNOWN;
 32 
 33    private int maxProcLength;
 34    private String productName;
 35    
 36    /**
 37     * Initializes the object by reading the metadata of this database.
 38     * @param pool the pool must be non null and initialized.
 39     * @throws Exception If a backend exception occurs.
 40     * 
 41     */
 42    public DbMetaHelper(I_DbPool pool) throws Exception {
 43       if (pool == null)
 44          throw new Exception("DbMetaHelper constructor: the pool is null");
 45       Connection conn = null;
 46       try {
 47          conn = pool.reserve();
 48          DatabaseMetaData meta = conn.getMetaData();
 49          
 50          this.maxProcLength = meta.getMaxProcedureNameLength();
 51          
 52          if (meta.storesLowerCaseIdentifiers())
 53             this.caseSense = CASE_LOWER;
 54          else if (meta.storesUpperCaseIdentifiers())
 55             this.caseSense = CASE_UPPER;
 56          else if (meta.storesMixedCaseIdentifiers())
 57             this.caseSense = CASE_MIXED;
 58          else
 59             throw new Exception("DbMetaHelper constructor: can not determine which case the identifiers are stored");
 60          String tmp = meta.getDatabaseProductName();
 61          if (tmp != null)
 62             this.productName = tmp.trim().toUpperCase();
 63          else
 64             this.productName = "";
 65       }
 66       finally {
 67          if (conn != null)
 68             pool.release(conn);
 69       }
 70    }
 71    
 72    
 73    /**
 74     * Returns an array of column names correctly sorted of the specified table.
 75     * Never returns null, if no columns found it returns an empty array.
 76     * @throws Exception If a backend exception occurs.
 77     * 
 78     */
 79    public String[] getColumnNames(I_DbPool pool, String catalog, String schema, String table) throws Exception {
 80       if (pool == null)
 81          throw new Exception("DbMetaHelper.getColumnNames: the pool is null");
 82       Connection conn = null;
 83       ResultSet rs = null;
 84       int count = 0;
 85       try {
 86          conn = pool.reserve();
 87          DatabaseMetaData meta = conn.getMetaData();
 88          if (catalog != null)
 89             catalog = getIdentifier(catalog.trim());
 90          if (schema != null)
 91             schema = getIdentifier(schema.trim());
 92          if (table != null)
 93             table = getIdentifier(table.trim());
 94          TreeMap map = new TreeMap();
 95          rs = meta.getColumns(catalog, schema, table, null);
 96          while (rs.next()) {
 97             int pos = rs.getInt("ORDINAL_POSITION");
 98             String name = rs.getString("COLUMN_NAME");
 99             // should already be in the correct order according to 
100             // javadoc but to be really sure we order it too
101             map.put(new Integer(pos), name);
102             count++;
103          }
104          if (count != map.size())
105             throw new Exception("Probably multiple tables '" + table + "' found since more columns with same ordinal position found");
106          return (String[])map.values().toArray(new String[map.size()]);
107       }
108       finally {
109          try {
110             if (rs != null)
111                rs.close();
112          }
113          catch (SQLException ex) {
114             ex.printStackTrace();
115          }
116          if (conn != null)
117             pool.release(conn);
118       }
119    }
120    
121    
122    /**
123     * Returns the correct identifier depending on the properties of the database. If it can not
124     * determine the case of the identifier it returns null.
125     * @param proposedName the name which is proposed.
126     * @return
127     */
128    public String getIdentifier(String proposedName) {
129       if (proposedName == null)
130          return null;
131       switch (this.caseSense) {
132       case CASE_MIXED : return proposedName;
133       case CASE_UPPER : return proposedName.toUpperCase();
134       case CASE_LOWER : return proposedName.toLowerCase();
135       default:return null; 
136       }
137    }
138    
139 
140    /**
141     * If the name is too long it cuts first from the end of the schema, and then from the end of the
142     * table name. Otherwise it is ${PREFIX}${SEP}${SCHEMA}${SEP}${TABLENAME}
143     * @param schema
144     * @param tableName
145     * @return
146     */
147    public String createFunctionName(String prefix, String separator, String schema, String tableName) {
148       if (schema == null)
149          schema = "";
150       if (prefix == null)
151          prefix = "";
152       if (separator == null)
153          separator = "";
154       StringBuffer buf = new StringBuffer(this.maxProcLength);
155       buf.append(getIdentifier(prefix)).append(separator).append(getIdentifier(schema)).append(separator).append(getIdentifier(tableName));
156       if (buf.length() < this.maxProcLength)
157          return buf.toString();
158       int toCut = buf.length() - this.maxProcLength;
159       if (toCut >= schema.length()) {
160          toCut -= schema.length();
161          schema = "";
162       }
163       else {
164          schema = schema.substring(0, schema.length() - toCut);
165       }
166       if (toCut > 0)
167          tableName = tableName.substring(0, tableName.length() - toCut);
168       return createFunctionName(prefix, separator, schema, tableName);
169    }
170    
171    public boolean isOracle() {
172       return this.productName.indexOf("ORACLE") != -1;
173    }
174 }


syntax highlighted by Code2HTML, v. 0.9.1