001    package com.sptci.rwt;
002    
003    import java.sql.Connection;
004    import java.sql.DatabaseMetaData;
005    import java.sql.ResultSet;
006    import java.sql.SQLException;
007    
008    import java.util.ArrayList;
009    import java.util.Collection;
010    import java.util.TreeMap;
011    
012    import com.sptci.util.CloseJDBCResources;
013    
014    /**
015     * An analyser for analysing index columns for tables in the database.
016     *
017     * <p>&copy; Copyright 2007 <a href='http://sptci.com/' target='_new'>Sans Pareil Technologies, Inc.</a></p>
018     * @author Rakesh Vidyadharan 2007-09-25
019     * @version $Id: IndexAnalyser.java 4123 2008-05-25 21:49:01Z rakesh $
020     * @see java.sql.DatabaseMetaData#getIndexInfo
021     */
022    public class IndexAnalyser extends KeyAnalyser
023    {
024      /**
025       * Create a new instance of the class using the specified connection
026       * manager.
027       *
028       * @param manager The manager for obtaining database connections.
029       */
030      public IndexAnalyser( final ConnectionManager manager )
031      {
032        super( manager );
033      }
034    
035      /**
036       * Returns a collection of {@link IndexMetaData} objects that
037       * contain all information pertaining to the indices for the
038       * specified table.
039       *
040       * @see Analyser#analyse
041       * @see #getNames
042       * @param parameters Must contain two parameters which are the names of
043       *   the <code>catalog/schema</code> and table from which index metadata
044       *   are to be retrieved.
045       */
046      @Override
047      public Collection<IndexMetaData> analyse( final MetaData... parameters )
048        throws SQLException
049      {
050        final TreeMap<String,IndexMetaData> md =
051          new TreeMap<String,IndexMetaData>();
052        Connection connection = null;
053        ResultSet resultSet = null;
054    
055        try
056        {
057          final CatalogueSchema cs = getNames( parameters[0] );
058          final TableMetaData tmd = (TableMetaData) parameters[1];
059    
060          connection = manager.open();
061          final DatabaseMetaData dmd = connection.getMetaData();
062          resultSet = dmd.getIndexInfo(
063              cs.getCatalogue(), cs.getSchema(), tmd.getName(), false, false );
064          
065          boolean first = true;
066          while ( resultSet.next() )
067          {
068            if ( first )
069            {
070              checkTableColumns( tmd );
071              first = false;
072            }
073    
074            final String name = resultSet.getString( "index_name" );
075            if ( name != null )
076            {
077              IndexMetaData imd = md.get( name );
078    
079              if ( imd == null )
080              {
081                imd = new IndexMetaData();
082                imd.setName( name );
083                imd.setUnique( ! resultSet.getBoolean( "non_unique" ) );
084                imd.setType( processType( resultSet.getShort( "type" ) ) );
085                imd.setPages( resultSet.getInt( "pages" ) );
086                imd.setCardinality( resultSet.getInt( "cardinality" ) );
087                imd.setSortSequence(
088                    processSortSequence( resultSet.getString( "asc_or_desc" ) ) );
089                imd.setTable( tmd );
090    
091                md.put( name, imd );
092              }
093    
094              imd.addColumn( tmd.getColumn( resultSet.getString( "column_name" ) ) );
095            }
096          }
097    
098          tmd.addIndices( md.values() );
099        }
100        finally
101        {
102          CloseJDBCResources.close( resultSet );
103          CloseJDBCResources.close( connection );
104        }
105    
106        return md.values();
107      }
108    
109      /**
110       * Process the <code>type</code> values and match
111       * them with the appropriate {@link IndexMetaData.Type} value.
112       *
113       * @param value The the short value read from result set.
114       * @return The appropriate type value.
115       */
116      protected IndexMetaData.Type processType( final short value )
117      {
118        IndexMetaData.Type rule = null;
119    
120        switch ( value )
121        {
122          case DatabaseMetaData.tableIndexStatistic :
123            rule = IndexMetaData.Type.Statistic;
124            break;
125          case DatabaseMetaData.tableIndexClustered :
126            rule = IndexMetaData.Type.Clustered;
127            break;
128          case DatabaseMetaData.tableIndexHashed :
129            rule = IndexMetaData.Type.Hashed;
130            break;
131          case DatabaseMetaData.tableIndexOther :
132            rule = IndexMetaData.Type.Other;
133            break;
134        };
135    
136        return rule;
137      }
138    
139      /**
140       * Process the <code>asc_or_desc</code> value and match them with the
141       * appropriate {@link IndexMetaData.SortSequence} value.
142       *
143       * @param value The the short value read from result set.
144       * @return The appropriate sort order value.
145       */
146      protected IndexMetaData.SortSequence processSortSequence(
147          final String value )
148      {
149        IndexMetaData.SortSequence order = null;
150    
151        if ( "A".equalsIgnoreCase( value ) )
152        {
153          order = IndexMetaData.SortSequence.Ascending;
154        }
155        else if ( "D".equalsIgnoreCase( value ) )
156        {
157          order = IndexMetaData.SortSequence.Descending;
158        }
159        else
160        {
161          order = IndexMetaData.SortSequence.Unsorted;
162        }
163    
164        return order;
165      }
166    }