JDocCoverage Report - 21.04.2006 22:02:51

Namemethod, %comment, %TODO@see
smallsql.database.Join158,0%   (327/3749)10

/* =============================================================
 * 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.]
 *
 * ---------------
 * Join.java
 * ---------------
 * Author: Volker Berlin
 * 
 */
package smallsql.database;


final class Join extends RowSource{

    Expression condition; // the join condition, the part after the ON
    private int type;
    RowSource left; // the left table, view or rowsource of the join
    RowSource right;
    private boolean isBeforeFirst = true;
	private boolean isAfterLast;
    private boolean isOuterValid = true;
	
	// Variables for FULL JOIN
    private boolean[] isFullNotValid;
    private int fullRightRowCounter;
    private int fullRowCount;
    private int fullReturnCounter = -1;
	
    private LongLongList rowPositions; // needed for getRowPosition() and setRowPosition()
    private int row; //current row number
    

    Join( int type, RowSource left, RowSource right, Expression condition ){
        this.type = type;
        this.condition = condition;
        this.left = left;
        this.right = right;
        if(type == FULL_JOIN){
        	isFullNotValid = new boolean[10];
        }
    }
    
    
	final boolean isScrollable(){
		return false; //TODO performance, if left and right are scrollable then this should also scrollable
	}

    
    void beforeFirst() throws Exception{
		left.beforeFirst();
		right.beforeFirst();
		isBeforeFirst = true;
		isAfterLast  = false;
		fullRightRowCounter = 0;
		fullRowCount        = 0;
		fullReturnCounter   = -1;
		row = 0;
    }

    boolean first() throws Exception{
        boolean result = left.first() && right.first();
        row = 1;
		isBeforeFirst= false;
		isAfterLast  = false;
        if(!result) noRow();
		return result;
    }
    

    boolean next() throws Exception{
    	if(isAfterLast) return false;
        boolean result;
        row++;
		if(fullReturnCounter >=0){
			do{
				if(fullReturnCounter >= fullRowCount){
					noRow();
					return false; 
				}
				right.next();
			}while(isFullNotValid[fullReturnCounter++]);
			return true;
		}
        do{
            if(isBeforeFirst){               
                result = left.next();
				if(result){ 
                	result = right.first();
					if(!result){
						switch(type){
							case LEFT_JOIN:
							case FULL_JOIN:
								isOuterValid = false;
								isBeforeFirst = false;
								right.nullRow();
								return true;
						}
					}else fullRightRowCounter++;
				}else{
					// left does not include any row
					if(type == FULL_JOIN){
						while(right.next()){
							fullRightRowCounter++;
						}
						fullRowCount = fullRightRowCounter;
					}
				}
            }else{
                result = right.next();				
                if(!result){
                    switch(type){
                    	case LEFT_JOIN:
                    	case FULL_JOIN:
                    		if(isOuterValid){
                        		isOuterValid = false;
                        		right.nullRow();
	                            return true;
                    		}
                    		fullRowCount = Math.max( fullRowCount, fullRightRowCounter);
							fullRightRowCounter = 0;
                    }
                    isOuterValid = true;
                    result = left.next();
                    if(result){ 
	                    result = right.first();
						if(!result){
							switch(type){
								case LEFT_JOIN:
								case FULL_JOIN:
									isOuterValid = false;
									right.nullRow();
									return true;
							}
						}else fullRightRowCounter++;
					}
					
                }else fullRightRowCounter++;
            }
            isBeforeFirst = false;
        }while(result && !getBoolean());
		isOuterValid = false;
		if(type == FULL_JOIN){
			if(fullRightRowCounter >= isFullNotValid.length){
				boolean[] temp = new boolean[fullRightRowCounter << 1];
				System.arraycopy( isFullNotValid, 0, temp, 0, fullRightRowCounter);
				isFullNotValid = temp;
			}
			if(!result){
				if(fullRowCount == 0){
					noRow();
					return false; 
				}
				if(fullReturnCounter<0) {
					fullReturnCounter = 0;
					right.first();
					left.nullRow();
				}
				while(isFullNotValid[fullReturnCounter++]){
					if(fullReturnCounter >= fullRowCount){
						noRow();
						return false; 
					}
					right.next();
				}
				return true;
			}else
				isFullNotValid[fullRightRowCounter-1] = result;
		}
		if(!result){
			noRow();
		}
        return result;
    }
    
    
	void afterLast(){
		isAfterLast = true;
		noRow();
	}
	
    
	int getRow(){
		return row;
	}
	
    
	final long getRowPosition(){
		if(rowPositions == null) rowPositions = new LongLongList();
		rowPositions.add( left.getRowPosition(), right.getRowPosition());
		return rowPositions.size()-1;
	}
	
	final void setRowPosition(long rowPosition) throws Exception{
		left .setRowPosition( rowPositions.get1((int)rowPosition));
		right.setRowPosition( rowPositions.get2((int)rowPosition));
	}
	

	final boolean rowInserted(){
		return left.rowInserted() || right.rowInserted();
	}
	
	
	final boolean rowDeleted(){
		return left.rowDeleted() || right.rowDeleted();
	}
	
	
    /**
     * By OUTER or FULL JOIN must one rowsource set to null.
     */
    void nullRow(){
    	left.nullRow();
    	right.nullRow();
    	row = 0;
    }
    

	void noRow(){
		isAfterLast = true;
		left.noRow();
		right.noRow();
		row = 0;
	}

    
    void execute() throws Exception{
    	left.execute();
    	right.execute();
    }
    

    private boolean getBoolean() throws Exception{
        return type == CROSS_JOIN || condition.getBoolean();
    }
    

    static final int CROSS_JOIN = 1;
    static final int INNER_JOIN = 2;
    static final int LEFT_JOIN  = 3;
    static final int FULL_JOIN  = 4;
	static final int RIGHT_JOIN = 5;
}