JDocCoverage Report - 21.04.2006 22:02:51

Namemethod, %comment, %TODO@see
smallsql.database.IndexDescription1721,5%   (1000/3662)11

/* =============================================================
 * SmallSQL : a free Java DBMS library for the Java(tm) platform
 * =============================================================
 *
 * (C) Copyright 2004-2006, by Volker Berlin.
 *
 * Project Info:  http://www.smallsql.de/
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but 
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
 * License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
 * USA.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 *
 * ---------------
 * IndexDescription.java
 * ---------------
 * Author: Volker Berlin
 * 
 * Created on 19.04.2005
 */
package smallsql.database;

import java.io.File;
import java.io.RandomAccessFile;
import java.sql.SQLException;



final class IndexDescription {

	static final int MAGIC_INDEX = 'S' << 24 | 'Q' << 16 | 'L' << 8 | 'I';
	static final int INDEX_VERSION = 1;
	
	private String name;
	final private int constraintType; //PRIMARY, UNIQUE, FORGAIN, INDEX
	final private Strings columns;
	private int[] matrix;
	final private Expressions expressions;
	private Index index;
	
	
	/**
	 * 
	 * @param constraintType one of SQLTokenizer.PRIMARY, SQLTokenizer.UNIQUE, SQLTokenizer.FOREIGN or SQLTokenizer.INDEX.
	 * @param columns the Expressions that build the index. For example one or more database columns.
	 */
	IndexDescription(int constraintType, Expressions expressions, Strings columns){
		this.constraintType = constraintType;
		this.expressions = expressions;
		this.columns = columns;
	}
	
	
	final void setName(String name){
		this.name = name;
	}
	
	
	final String getName(){
		return name;
	}
	
	
	final boolean isPrimary(){
		return constraintType == SQLTokenizer.PRIMARY;
	}
	
	
	final boolean isUnique(){
		return constraintType == SQLTokenizer.PRIMARY || constraintType == SQLTokenizer.UNIQUE;
	}
	
	
	final Strings getColumns(){
		return columns;
	}
	
	
	/**
	 * Descript how well the index match to the column list.
	 * @param strings a list of columns that should match
	 * @return Integer.MAX_VALUE does not match; 0 - 100% match
	 */
	final int matchFactor(Strings strings){
		if(strings.size() < columns.size())
			return Integer.MAX_VALUE; //does not map
		
		nextColumn:
		for(int c=0; c<columns.size(); c++){
			String colName = columns.get(c);
			for(int s=0; s<strings.size(); s++){
				if(colName.equalsIgnoreCase(strings.get(s)) )
					continue nextColumn;
			}
			return Integer.MAX_VALUE; //No Strin found for colName
		}
		return strings.size() - columns.size();
	}
	
	
	/**
	 * Create a binding of the columns form this index to the columns of the table.
	 * @param database 
	 * @param tableView
	 * @see IndexDescriptions#setTableView
	 */
	final void init(Database database, TableView tableView)/* throws Exception*/{
		int size = tableView.columns.size();
		matrix = new int[size];
		for(int i=0; i<matrix.length; i++){
			matrix[i] = -1;
		}
		
		for(int i=0; i<columns.size(); i++){
			matrix[tableView.findColumnIdx(columns.get(i))] = i;
		}
		if(name == null){
			name = tableView.name + "_" + Long.toHexString(System.currentTimeMillis()) + Integer.toHexString(hashCode());
		}
		
	}
	
	
	/**
	 * Create the index. A file for storing the index data is saved.
	 */
	final void create(Database database, TableView tableView) throws Exception{
		init( database, tableView );
		createFile( database ).close();
	}
	
	
	static File getFile(Database database, String name) throws Exception{
		return new File( Utils.createIdxFileName( database, name ) );
	}
	

	private RandomAccessFile createFile(Database database) throws Exception{
		File file = getFile( database, name );
		boolean ok = file.createNewFile();
		if(!ok) throw Utils.createSQLException("Index '" + name + "' allready exists.");
		RandomAccessFile raFile = new RandomAccessFile( file, "rw" );
		writeMagic(raFile);
		return raFile;
	}
	

	public void drop(Database database) throws Exception {
		boolean ok = getFile( database, name).delete();
		if(!ok) throw Utils.createSQLException("Table '" + name + "' can't drop.");
	}

	private final void writeMagic(RandomAccessFile raFile) throws Exception{
		raFile.writeInt(MAGIC_INDEX);
		raFile.writeInt(INDEX_VERSION);
	}


	/**
	 * This is call if a single colum of the table is changed.
	 * @param columnIdx The column position in the table
	 * @param valueExpression the new value of the current row.
	 */
	final void writeExpression( int columnIdx, Expression valueExpression) {
		int idx = matrix[columnIdx];
		if(idx >= 0) //set only if the column part of this index
			expressions.set(idx, valueExpression);
	}


	/**
	 * This is call if the row is finsch written.
	 * @param con the connection for a later commit or rollback.
	 */
	final void writeFinsh(SSConnection con) {
		//TODO
		//index.addValues(expressions);		
	}
	
	
	/**
	 * Save this IndexDescription in the Table definition.
	 */
	final void save(StoreImpl store) throws SQLException{
		store.writeInt(constraintType);
		store.writeInt(columns.size());
		for(int c=0; c<columns.size(); c++){
			store.writeString( columns.get(c) );
		}
		store.writeString(name);
	}
	
	
	/**
	 * Restore a IndexDescription from a saved Table.
	 */
	final static IndexDescription load(Database database, TableView tableView, StoreImpl store) throws SQLException{
		int constraintType = store.readInt();
		int count = store.readInt();
		Strings columns = new Strings();
		Expressions expressions = new Expressions();
		SQLParser sqlParser = new SQLParser();
		for(int c=0; c<count; c++){
			String column = store.readString();
			columns.add( column );
			expressions.add( sqlParser.parseExpression(column));
		}
		IndexDescription indexDesc = new IndexDescription(constraintType, expressions, columns);
		indexDesc.setName( store.readString() );
		indexDesc.init( database, tableView );
		return indexDesc;
	}


}