/*
* Copyright (C) 2000 - 2008 TagServlet Ltd
*
* This file is part of Open BlueDragon (OpenBD) CFML Server Engine.
*
* OpenBD is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* Free Software Foundation,version 3.
*
* OpenBD 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenBD. If not, see http://www.gnu.org/licenses/
*
* Additional permission under GNU GPL version 3 section 7
*
* If you modify this Program, or any covered work, by linking or combining
* it with any of the JARS listed in the README.txt (or a modified version of
* (that library), containing parts covered by the terms of that JAR, the
* licensors of this Program grant you additional permission to convey the
* resulting work.
* README.txt @ http://www.openbluedragon.org/license/README.txt
*
* http://www.openbluedragon.org/
*/
package com.naryx.tagfusion.cfm.queryofqueries;
/**
* This class represents the result table from a select statement
* where the select is not a group by but contains expressions
* in the select columns. Only one row of data is returned in the
* result.
*/
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import com.naryx.tagfusion.cfm.engine.cfData;
import com.naryx.tagfusion.cfm.engine.cfmRunTimeException;
class groupByResultTable extends resultTable{
// the first groupby column, subsequent groupby cols are hashtables within this one
private Hashtable groupBy;
private List<columnRef> groupByList; // arraylist of columnRef's
private condition havingCondition;
public groupByResultTable( selectColumn[] _selCols, orderByCol [] _orderBy, List<columnRef> _groupByList, condition _havingCondition, boolean _distinct ){
super( _selCols, _distinct, _orderBy );
havingCondition = _havingCondition;
groupByList = _groupByList;
groupBy = new Hashtable();
}// groupByResultTable()
public void processRow( rowContext _rowcontext, List<cfData> _pData, Map<String, String> _lookup ) throws cfmRunTimeException{
cfData [] result;
groupByResultRow row = getRow( _rowcontext, _pData );
row.rowData.clear();
cfData nextItem;
for ( int i = 0; i < row.cols.length; i++ ){ // each selectColumn
result = row.cols[i].execute( _rowcontext, _pData );
for ( int j = 0; j < result.length; j++ ){
nextItem = result[j].duplicate();
row.rowData.add( nextItem );
}
}
if ( orderCols != null && row.orderData.size() == 0 ){
initOrderByIndex( _rowcontext );
for ( int i = 0; i < orderCols.length; i++ ){
if ( orderByIndx[i] != -1 ){
row.orderData.add( row.rowData.get( orderByIndx[i] ) );
}else{
int tablenameIndx = orderCols[i].getColName().indexOf( '.' );
cfData val = null;
if ( tablenameIndx != -1 ){
val = _rowcontext.get( orderCols[i].getColName().substring( 0, tablenameIndx ), orderCols[i].getColName().substring( tablenameIndx+1 ) );
}else{
val = _rowcontext.get( orderCols[i].getColName() );
}
row.orderData.add( val );
}
}
}
}
// get the selectCol[] / arraylist from the hashtable
// by getting the values of the group by columns from the rowcontext
private groupByResultRow getRow( rowContext _rowContext, List<cfData> _pData ) throws cfmRunTimeException{
Hashtable ht = groupBy;
groupByResultRow rowData = null; // not arraylist
for ( int i = 0; i < groupByList.size(); i++ ){
String index = ( groupByList.get( i ) ).evaluate( _rowContext, _pData ).getString();
if ( ht.containsKey( index ) ){
if ( i == groupByList.size() - 1 ){
rowData = (groupByResultRow) ht.get( index );
}else{
ht = (Hashtable) ht.get( index );
}
}else{
// create it
if ( i == groupByList.size() - 1 ){
// create new selectCol/arraylist copying selectCols
rowData = new groupByResultRow( getSelectColumnsCopy() );
ht.put( index, rowData );
}else{
Hashtable temp = new Hashtable();
ht.put( index, temp );
ht = temp;
//rowData = (datatype) ht.get( index );
}
}
}
return rowData;
}// getRow()
/**
* returns a List of Lists of cfData this is the data from the
* result table
*
* @throws cfmRunTimeException
*/
public List<ResultRow> getResultData( Map<String, Integer> _indxLookup ) throws cfmRunTimeException {
// iterate thru the hashtable adding all the arraylists
getArrayListsFromHashtable( groupBy, groupByList.size(), this.resultRows );
// if DISTINCT, then remove all the duplicate rows
if ( distinct ) {
List<ResultRow> distinctRows = new ArrayList<ResultRow>();
for ( int i = 0; i < this.resultRows.size(); i++ ) {
ResultRow row = this.resultRows.get( i );
if ( !listContains( distinctRows, row ) ) {
distinctRows.add( row );
}
}
this.resultRows = distinctRows;
}
if ( this.havingCondition != null ) {
List<ResultRow> selectedRows = new ArrayList<ResultRow>();
for ( int i = 0; i < this.resultRows.size(); i++ ) {
ResultRow row = this.resultRows.get( i );
if ( this.havingCondition.evaluate( row, null, _indxLookup ) ) {
selectedRows.add( row );
}
}
this.resultRows = selectedRows;
}
return this.resultRows;
}// getResultData()
private void getArrayListsFromHashtable( Hashtable _ht, int _depth, List<ResultRow> _outList ){
if ( _depth == 1 ){
Enumeration rows = _ht.elements();
while( rows.hasMoreElements() ){
groupByResultRow nextRow = (groupByResultRow) rows.nextElement();
_outList.add( new ResultRow( nextRow.rowData, nextRow.orderData ) );
}
}else{
Enumeration elements = _ht.elements();
while ( elements.hasMoreElements() ){
getArrayListsFromHashtable( (Hashtable) elements.nextElement(), _depth - 1, _outList );
}
}
}
/**
* This returns shallow copies of the select columns in this result table.
* The main reason for this method is that functions will be deep copied,
* facilitating the group by.
*/
private selectColumn[] getSelectColumnsCopy(){
int no_cols = selCols.length;
selectColumn[] colCopies = new selectColumn[ no_cols ];
for ( int i = 0; i < no_cols; i++ ){
colCopies[i] = selCols[i].shallowCopy();
}
return colCopies;
}// getSelectColumnsCopy()
class groupByResultRow {
private selectColumn [] cols;
private List<cfData> rowData;
private List<cfData> orderData;
public groupByResultRow( selectColumn [] _selCols ){
cols = _selCols;
rowData = new ArrayList<cfData>();
orderData = new ArrayList<cfData>();
}
}
}