EMMA Coverage Report (generated Wed Jun 28 19:54:35 CEST 2006)
[all classes][smallsql.database]

COVERAGE SUMMARY FOR SOURCE FILE [GroupResult.java]

nameclass, %method, %block, %line, %
GroupResult.java100% (1/1)100% (9/9)95%  (423/443)98%  (99,8/102)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class GroupResult100% (1/1)100% (9/9)95%  (423/443)98%  (99,8/102)
addInternalExpressionFromGroupBy (Expression): int 100% (1/1)64%  (23/36)82%  (5,8/7)
GroupResult (CommandSelect, RowSource, Expressions, Expression, Expressions):... 100% (1/1)93%  (99/106)95%  (21/22)
accumulateRow (): void 100% (1/1)100% (21/21)100% (4/4)
addGroupRow (): void 100% (1/1)100% (40/40)100% (8/8)
addInternalExpressionFromSelect (Expression): int 100% (1/1)100% (78/78)100% (17/17)
execute (): void 100% (1/1)100% (41/41)100% (14/14)
patchExpression (Expression): Expression 100% (1/1)100% (78/78)100% (21/21)
patchExpressions (Expression): void 100% (1/1)100% (23/23)100% (5/5)
patchExpressions (Expressions): void 100% (1/1)100% (20/20)100% (4/4)

1/* =============================================================
2 * SmallSQL : a free Java DBMS library for the Java(tm) platform
3 * =============================================================
4 *
5 * (C) Copyright 2004-2006, by Volker Berlin.
6 *
7 * Project Info:  http://www.smallsql.de/
8 *
9 * This library is free software; you can redistribute it and/or modify it 
10 * under the terms of the GNU Lesser General Public License as published by 
11 * the Free Software Foundation; either version 2.1 of the License, or 
12 * (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful, but 
15 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
16 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 
17 * License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
22 * USA.  
23 *
24 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
25 * in the United States and other countries.]
26 *
27 * ---------------
28 * GroupResult.java
29 * ---------------
30 * Author: Volker Berlin
31 * 
32 */
33package smallsql.database;
34 
35import java.sql.*;
36 
37/**
38 * @author Volker Berlin
39 *
40 */
41class GroupResult extends MemoryResult{
42 
43        private Expression currentGroup; //Validate if the current row of cmd is part of the current group
44        private RowSource from;
45        private Expressions groupBy; // the list of Expressions in the GROUP BY clause
46    private Expressions expressions = new Expressions(); // List of Expression
47        private Expressions internalExpressions = new Expressions(); // a list of Aggregate Function and ColNames from SELECT, GROUP BY and HAVING
48        
49        /**
50         * Constructor for Grouping a Result from a CommandSelect
51         */
52        GroupResult(CommandSelect cmd, RowSource from, Expressions groupBy, Expression having, Expressions orderBy) throws SQLException{
53                this.from = from;
54                this.groupBy = groupBy;
55                
56                if(groupBy != null){
57                        for(int i=0; i<groupBy.size(); i++){
58                                Expression left = groupBy.get(i);
59                                int idx = addInternalExpressionFromGroupBy( left );
60                                ExpressionName right = new ExpressionName(null);
61                                right.setFrom(this, idx, new ColumnExpression(left));
62                                Expression expr = new ExpressionArithmetic( left, right, ExpressionArithmetic.EQUALS_NULL);
63                                currentGroup = (currentGroup == null) ? 
64                                                                expr :
65                                                                new ExpressionArithmetic( currentGroup, expr, ExpressionArithmetic.AND );
66                        }
67                }
68                expressions = internalExpressions;
69        for(int c=0; c<expressions.size(); c++){
70            addColumn(new ColumnExpression(expressions.get(c)));
71        }
72 
73                patchExpressions( cmd.columnExpressions );
74                if(having != null) having = patchExpression( having );
75                patchExpressions( orderBy );
76        }
77        
78        /**
79         * Add a expression to the internal expression list if not exist in this list.
80         * It will be added named columns in the GROUP BY clause.
81         * @param expr The expression to added.
82         * @return the position in the internal list
83         */
84        final private int addInternalExpressionFromGroupBy(Expression expr) throws SQLException{
85                int type = expr.getType();
86                if(type >= Expression.GROUP_BEGIN){
87                                throw Utils.createSQLException("Aggregate function are not valid in the GROUP BY clause. ("+expr+")");
88                }else{
89                        int idx = internalExpressions.indexOf(expr);
90                        if(idx >= 0) return idx;
91                        internalExpressions.add(expr);
92                        return internalExpressions.size()-1;
93                }
94        }
95        
96        
97        /**
98         * Add a expression to the internal expression list if not exist in this list.
99         * It will be added aggregate functions from the SELECT, HAVING and ORDER BY clause.
100         * @param expr The expression to added.
101         * @return the position in the internal list
102         */
103        final private int addInternalExpressionFromSelect(Expression expr) throws SQLException{
104                int type = expr.getType();
105                if(type == Expression.NAME){
106                        int idx = internalExpressions.indexOf(expr);
107                        if(idx >= 0) return idx;
108                        throw Utils.createSQLException("Expression '" + expr + "' is not part of a aggregate function or GROUP BY clause.");
109                }else
110                if(type >= Expression.GROUP_BEGIN){
111                        int idx = internalExpressions.indexOf(expr);
112                        if(idx >= 0) return idx;
113                        internalExpressions.add(expr);
114                        return internalExpressions.size()-1;
115                }else{
116                        //if a function or aritmethik expresion is already in the group by the it is ok
117                        int idx = internalExpressions.indexOf(expr);
118                        if(idx >= 0) return idx;
119                        Expression[] params = expr.getParams();
120                        if(params != null){
121                                for(int p=0; p<params.length; p++){
122                                        addInternalExpressionFromSelect( params[p]);
123                                }
124                        }
125                        return -1;
126                }
127        }
128        
129        
130        /**
131         * Patch all external ExpressionName in the list (SELECT clause)
132         * that it link to the the internal RowSource.
133         */
134        final private void patchExpressions(Expressions exprs) throws SQLException{
135                if(exprs == null) return;
136                for(int i=0; i<exprs.size(); i++){
137                        exprs.set(i, patchExpression(exprs.get(i)));
138                }        
139        }
140        
141        
142        final private void patchExpressions(Expression expression) throws SQLException{
143                Expression[] params = expression.getParams();
144                if(params == null) return;
145                for(int i=0; i<params.length; i++){
146                        expression.setParamAt( patchExpression(params[i]), i);
147                }
148        }
149        
150        
151        /**
152         * Patch a single Expression. The caller need to replace the original Object
153         * if the return value return another object.
154         * @param expr the Expression to patch
155         * @return on simple columns and Aggregatfunction the original Expression is return as patch.
156         */
157        final private Expression patchExpression(Expression expr) throws SQLException{
158                //find the index in the internalExpression list
159                int idx = addInternalExpressionFromSelect( expr );
160                if(idx>=0){
161            Expression origExpression = expr;
162                        ExpressionName exprName;
163                        if(expr instanceof ExpressionName){
164                                exprName = (ExpressionName)expr;
165                        }else{
166                                // this can only occur if in the GROUP BY clause are a function or arithmetic expression
167                                // and a equals expression is used in SELECT, GROUP BY or HAVING
168                                expr = exprName = new ExpressionName(expr.getAlias());
169                        }
170                        // patch the expression and set a new DataSource
171                        Column column = exprName.getColumn();
172                        if(column == null){
173                                column = new Column();
174                exprName.setFrom(this, idx, column);
175                                switch(exprName.getType()){
176                                        case Expression.MAX:
177                                        case Expression.MIN:
178                                        case Expression.FIRST:
179                                        case Expression.LAST:
180                                        case Expression.SUM:
181                                                Expression baseExpression = exprName.getParams()[0];
182                                                column.setPrecision(baseExpression.getPrecision());
183                                                column.setScale(baseExpression.getScale());
184                                                break;
185                    default:
186                        column.setPrecision(origExpression.getPrecision());
187                        column.setScale(origExpression.getScale());
188                                }
189                                column.setDataType(exprName.getDataType());
190                        }else{
191                                exprName.setFrom(this, idx, column);
192                        }
193                }else{
194                        patchExpressions(expr);
195                }
196                return expr;
197        }
198 
199        
200        
201        final void execute() throws Exception{
202        super.execute();
203                from.execute();
204                NextRow:
205                while(from.next()){
206                        beforeFirst();
207                        while(next()){
208                                if(currentGroup == null || currentGroup.getBoolean()){
209                                        accumulateRow();
210                                        continue NextRow;
211                                }
212                        }
213                        // add a new row to the GroupResult
214                        addGroupRow();
215                        accumulateRow();
216                }
217                
218                if(getRowCount() == 0 && groupBy == null){
219                        //special handling for SELECT count(*) FROM table
220                        //without GROUP BY and without any rows
221                        addGroupRow();
222                }
223                // reset the row counter
224                beforeFirst();
225        }
226        
227        
228        
229        /**
230         * Add a new Row to the MemoryResult. This occur because the 
231         * GROUP BY clause of the current row not relate to an exists row. 
232         *
233         */
234        final private void addGroupRow(){
235                // add a new row to the GroupResult
236                ExpressionValue[] newRow = currentRow = new ExpressionValue[ expressions.size()];
237                for(int i=0; i<newRow.length; i++){
238                        Expression expr = expressions.get(i);
239                        int type = expr.getType();
240                        if(type < Expression.GROUP_BEGIN) type = Expression.GROUP_BY; 
241                        newRow[i] = new ExpressionValue( type );
242                }
243                addRow(newRow);
244        }
245        
246        
247        final private void accumulateRow() throws Exception{
248                for(int i=0; i<currentRow.length; i++){
249                        Expression src = expressions.get(i);
250                        currentRow[i].accumulate(src);
251                }
252        }
253}

[all classes][smallsql.database]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov