Quadcap Embeddable Database

com/quadcap/sql/AggregateExpression.java

Go to the documentation of this file.
00001 package com.quadcap.sql; 00002 00003 /* Copyright 1999 - 2003 Quadcap Software. All rights reserved. 00004 * 00005 * This software is distributed under the Quadcap Free Software License. 00006 * This software may be used or modified for any purpose, personal or 00007 * commercial. Open Source redistributions are permitted. Commercial 00008 * redistribution of larger works derived from, or works which bundle 00009 * this software requires a "Commercial Redistribution License"; see 00010 * http://www.quadcap.com/purchase. 00011 * 00012 * Redistributions qualify as "Open Source" under one of the following terms: 00013 * 00014 * Redistributions are made at no charge beyond the reasonable cost of 00015 * materials and delivery. 00016 * 00017 * Redistributions are accompanied by a copy of the Source Code or by an 00018 * irrevocable offer to provide a copy of the Source Code for up to three 00019 * years at the cost of materials and delivery. Such redistributions 00020 * must allow further use, modification, and redistribution of the Source 00021 * Code under substantially the same terms as this license. 00022 * 00023 * Redistributions of source code must retain the copyright notices as they 00024 * appear in each source code file, these license terms, and the 00025 * disclaimer/limitation of liability set forth as paragraph 6 below. 00026 * 00027 * Redistributions in binary form must reproduce this Copyright Notice, 00028 * these license terms, and the disclaimer/limitation of liability set 00029 * forth as paragraph 6 below, in the documentation and/or other materials 00030 * provided with the distribution. 00031 * 00032 * The Software is provided on an "AS IS" basis. No warranty is 00033 * provided that the Software is free of defects, or fit for a 00034 * particular purpose. 00035 * 00036 * Limitation of Liability. Quadcap Software shall not be liable 00037 * for any damages suffered by the Licensee or any third party resulting 00038 * from use of the Software. 00039 */ 00040 00041 import java.io.Externalizable; 00042 import java.io.IOException; 00043 import java.io.ObjectInput; 00044 import java.io.ObjectOutput; 00045 00046 import java.util.Enumeration; 00047 import java.util.Vector; 00048 00049 import java.sql.SQLException; 00050 00051 import com.quadcap.sql.types.Op; 00052 import com.quadcap.sql.types.Type; 00053 import com.quadcap.sql.types.TypeInt; 00054 import com.quadcap.sql.types.Value; 00055 import com.quadcap.sql.types.ValueDouble; 00056 import com.quadcap.sql.types.ValueInteger; 00057 import com.quadcap.sql.types.ValueNull; 00058 00059 import com.quadcap.sql.index.Btree; 00060 00061 import com.quadcap.util.Debug; 00062 00063 /** 00064 * Expression implementing one of <b>AVG</b>, <b>SUM</b>, 00065 * <b>MIN</b>, or <b>MAX</b>. 00066 * 00067 * @author Stan Bailes 00068 */ 00069 public class AggregateExpression 00070 extends Expression implements Externalizable 00071 { 00072 public static final int AVG = 0; 00073 public static final int SUM = 1; 00074 public static final int MIN = 2; 00075 public static final int MAX = 3; 00076 public static final int COUNT = 4; 00077 00078 int op = -1; 00079 boolean all = false; 00080 Expression expr = null; 00081 00082 static String[] ops = {"AVG","SUM","MIN","MAX","COUNT"}; 00083 00084 static String toString(int op) { 00085 try { 00086 return ops[op]; 00087 } catch (Throwable y) { 00088 return "bad op<" + op + ">"; 00089 } 00090 } 00091 00092 static final byte[] aByte = { 0 }; 00093 00094 /** 00095 * Default constructor 00096 */ 00097 public AggregateExpression() {} 00098 00099 /** 00100 * Explicit constructor 00101 */ 00102 public AggregateExpression(int op, boolean all, Expression expr) { 00103 this.op = op; 00104 this.all = all; 00105 this.expr = expr; 00106 } 00107 00108 Expression getInnerExpression() { 00109 return expr; 00110 } 00111 00112 boolean isMin() { return op == MIN; } 00113 boolean isMax() { return op == MAX; } 00114 boolean isCount() { return op == COUNT; } 00115 00116 /** 00117 * Private class to maintain per-session state for this expression 00118 */ 00119 class AggregateSessionState implements StatementContext { 00120 Session session; 00121 Btree distinct = null; 00122 00123 Value accum = null; 00124 int count = 0; 00125 00126 public AggregateSessionState(Session session) { 00127 this.session = session; 00128 } 00129 00130 /** Whenever you get around to finishing me is fine. */ 00131 public int priority() { return 4; } 00132 00133 /** Girl I believe I got to move on down the line. */ 00134 public void finish(boolean abort) throws IOException { 00135 try { 00136 if (distinct != null) { 00137 distinct.free(); 00138 } 00139 } finally { 00140 if (distinct != null) session.getDatabase().releaseTempFile(); 00141 distinct = null; 00142 } 00143 } 00144 00145 /** Get ready for another day */ 00146 public void reset() throws IOException { 00147 count = 0; 00148 accum = null; 00149 finish(false); 00150 } 00151 } 00152 00153 public void reset(Session session) throws IOException { 00154 AggregateSessionState s = getSessionState(session); 00155 if (s != null) s.reset(); 00156 } 00157 00158 AggregateSessionState getSessionState(Session session) { 00159 return getSessionState(session, true); 00160 } 00161 00162 AggregateSessionState getSessionState(Session session, boolean mk) { 00163 AggregateSessionState s = (AggregateSessionState) 00164 session.getContext(this, false); 00165 if (s == null && mk) { 00166 s = new AggregateSessionState(session); 00167 session.putContext(this, false, s); 00168 } 00169 return s; 00170 } 00171 00172 public int rank() { return 0; } 00173 00174 public Type getType(Session session, Cursor cursor) 00175 throws SQLException 00176 { 00177 switch (op) { 00178 case COUNT: 00179 return TypeInt.typeInt; 00180 default: 00181 return expr.getType(session, cursor); 00182 } 00183 } 00184 00185 public Value getValue(Session session, Cursor cursor) 00186 throws SQLException 00187 { 00188 AggregateSessionState s = getSessionState(session); 00189 switch (op) { 00190 case AVG: 00191 if (s.accum == null) { 00192 return ValueNull.valueNull; 00193 } 00194 return Value.binop(Op.DIVIDE, s.accum, 00195 new ValueInteger(s.count)); 00196 case SUM: 00197 case MIN: 00198 case MAX: 00199 if (s.accum == null) return ValueNull.valueNull; 00200 return s.accum; 00201 case COUNT: 00202 return new ValueInteger(s.count); 00203 default: 00204 throw new SQLException("Bad aggregate type: " + op, "42000"); 00205 } 00206 } 00207 00208 public void updateAggregate(Session session, Cursor cursor) 00209 throws SQLException 00210 { 00211 AggregateSessionState s = getSessionState(session); 00212 Value v1 = null; 00213 if (cursor != null) { 00214 if (expr != null) { 00215 v1 = expr.getValue(session, cursor); 00216 } 00217 if (!Value.isNull(v1)) { 00218 if (all) { 00219 s.count++; 00220 } else { 00221 try { 00222 if (s.distinct == null) { 00223 s.distinct = session.makeTempTree(); 00224 } 00225 byte[] key = Value.bytes(v1); 00226 if (!s.distinct.set(key, key.length, 00227 aByte, 0, 1)) { 00228 s.count++; 00229 } else { 00230 v1 = ValueNull.valueNull; 00231 } 00232 } catch (IOException e) { 00233 throw DbException.wrapThrowable(e); 00234 } 00235 } 00236 } 00237 } else { 00238 v1 = ValueNull.valueNull; 00239 } 00240 switch (op) { 00241 case AVG: 00242 case SUM: 00243 if (!Value.isNull(v1)) { 00244 if (s.accum == null) { 00245 s.accum = v1; 00246 } else { 00247 s.accum = Value.binop(Op.PLUS, v1, s.accum); 00248 } 00249 } 00250 break; 00251 case MIN: 00252 if (!Value.isNull(v1)) { 00253 if (s.accum == null || Value.boolOp(Op.LT, v1, s.accum)) { 00254 s.accum = v1; 00255 } 00256 } 00257 break; 00258 case MAX: 00259 if (!Value.isNull(v1)) { 00260 if (s.accum == null || Value.boolOp(Op.GT, v1, s.accum)) { 00261 s.accum = v1; 00262 } 00263 } 00264 break; 00265 case COUNT: 00266 break; 00267 default: 00268 throw new SQLException("Bad aggregate type: " + op, "42000"); 00269 } 00270 } 00271 00272 public void invert() { 00273 } 00274 00275 public String toString() { 00276 StringBuffer sb = new StringBuffer(toString(op)); 00277 if (!all) sb.append(" DISTINCT"); 00278 sb.append(' '); 00279 sb.append(String.valueOf(expr)); 00280 return sb.toString(); 00281 } 00282 00283 public void visitSubExpressions(ExpressionVisitor ev) { 00284 ev.visit(expr); 00285 } 00286 00287 public void readExternal(ObjectInput in) 00288 throws IOException, ClassNotFoundException 00289 { 00290 expr = (Expression)in.readObject(); 00291 op = in.readInt(); 00292 all = (in.read() == 1); 00293 } 00294 00295 public void writeExternal(ObjectOutput out) throws IOException { 00296 out.writeObject(expr); 00297 out.writeInt(op); 00298 out.write(all ? 1 : 0); 00299 } 00300 }