1 33 package smallsql.database; 34 35 import java.sql.*; 36 37 41 class GroupResult extends MemoryResult{ 42 43 private Expression currentGroup; private RowSource from; 45 private Expressions groupBy; private Expressions expressions = new Expressions(); private Expressions internalExpressions = new Expressions(); 49 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 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 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 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 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 157 final private Expression patchExpression(Expression expr) throws SQLException{ 158 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 expr = exprName = new ExpressionName(expr.getAlias()); 169 } 170 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 addGroupRow(); 215 accumulateRow(); 216 } 217 218 if(getRowCount() == 0 && groupBy == null){ 219 addGroupRow(); 222 } 223 beforeFirst(); 225 } 226 227 228 229 234 final private void addGroupRow(){ 235 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 } 254 | Popular Tags |