Quadcap Embeddable Database

com/quadcap/sql/MergeCursor.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.ByteArrayInputStream; 00042 import java.io.Externalizable; 00043 import java.io.IOException; 00044 import java.io.ObjectInput; 00045 import java.io.ObjectOutput; 00046 00047 import java.util.Vector; 00048 00049 import java.sql.SQLException; 00050 00051 import com.quadcap.sql.io.ObjectInputStream; 00052 import com.quadcap.sql.io.ObjectOutputStream; 00053 00054 import com.quadcap.sql.file.ByteUtil; 00055 00056 import com.quadcap.sql.index.BCursor; 00057 import com.quadcap.sql.index.Btree; 00058 00059 import com.quadcap.sql.types.Op; 00060 import com.quadcap.sql.types.Value; 00061 00062 import com.quadcap.util.Debug; 00063 import com.quadcap.util.Util; 00064 00065 /** 00066 * Cursor implementing the SQL <b>UNION</b> or <b>INTERSECTION</b> operations. 00067 * This cursor shares some functionality with the GroupByCursor class, 00068 * and factorization should be investigated. 00069 * 00070 * @author Stan Bailes 00071 */ 00072 public class MergeCursor extends CursorImpl { 00073 int op; 00074 boolean all; 00075 TempTableMerge tempTable; 00076 LazyRow row = null; 00077 BCursor bc = null; 00078 int duplicateCount = 0; 00079 00080 public MergeCursor(Session session, int op, boolean all, 00081 TempTableMerge tempTable) 00082 throws SQLException 00083 { 00084 super(session, null, null); 00085 this.op = op; 00086 this.all = all; 00087 this.tempTable = tempTable; 00088 } 00089 00090 public Row getRow() throws SQLException { 00091 return row; 00092 } 00093 00094 public void checkCursor() throws IOException { 00095 if (bc == null) { 00096 bc = tempTable.getCursor(); 00097 } 00098 } 00099 00100 public long getRowId() { 00101 byte[] val = bc.getValBuf(); 00102 return val[0] == 1 ? 0 : ByteUtil.getLong(val, 1); 00103 } 00104 00105 public void resolveColumns() throws SQLException { 00106 super.resolveColumns(); 00107 row = new LazyRow(getColumnCount()); 00108 beforeFirst(); 00109 } 00110 00111 public String getName() { return ""; } 00112 00113 public long size() throws SQLException { 00114 try { 00115 checkCursor(); 00116 return bc.size(); 00117 } catch (IOException e) { 00118 throw DbException.wrapThrowable(e); 00119 } 00120 } 00121 00122 public void afterLast() throws SQLException { 00123 throw new SQLException("afterLast() not supported for this cursor type"); 00124 } 00125 00126 public boolean isWritable(int col) { return false; } 00127 00128 public boolean next() throws SQLException { 00129 try { 00130 checkCursor(); 00131 switch (op) { 00132 case Op.UNION: 00133 return all ? nextUnionAll() : nextUnion(); 00134 case Op.INTERSECT: 00135 return nextIntersect(); 00136 case Op.EXCEPT: 00137 return nextExcept(); 00138 default: 00139 throw new SQLException("Bad merge op: " + op, "42000"); 00140 } 00141 } catch (IOException e) { 00142 throw DbException.wrapThrowable(e); 00143 } 00144 } 00145 00146 public void updateRow(Row row) throws SQLException { 00147 throw new SQLException("GroupBy expressions aren't updateable", 00148 "42000"); 00149 } 00150 00151 public void deleteRow() throws SQLException { 00152 throw new SQLException("GroupBy expressions aren't updateable", 00153 "42000"); 00154 } 00155 00156 public void beforeFirst() throws SQLException { 00157 try { 00158 checkCursor(); 00159 bc.beforeFirst(); 00160 } catch (IOException e) { 00161 throw DbException.wrapThrowable(e); 00162 } finally { 00163 duplicateCount = 0; 00164 } 00165 } 00166 00167 /** 00168 * Separate from 'nextUnionAll' because we can avoid fetching the 00169 * data for this case. 00170 */ 00171 boolean nextUnion() throws SQLException, IOException { 00172 if (!bc.next()) return false; 00173 tempTable.getRow(bc.getValBuf(), row); 00174 return true; 00175 } 00176 00177 /** 00178 * Fetch the data once when we fetch the counts, then return each 00179 * row the required number of times 00180 */ 00181 boolean nextUnionAll() throws SQLException, IOException { 00182 if (duplicateCount-- <= 0) { 00183 if (!bc.next()) return false; 00184 tempTable.getRow(bc.getValBuf(), row); 00185 byte[] data = bc.getValBuf(); 00186 int acnt = TempTableMerge.getCount(data, 0); 00187 int bcnt = TempTableMerge.getCount(data, 1); 00188 duplicateCount = acnt + bcnt - 1; 00189 return true; 00190 } 00191 return true; 00192 } 00193 00194 boolean nextIntersect() throws SQLException, IOException { 00195 if (!all || duplicateCount-- <= 0) { 00196 boolean found = false; 00197 do { 00198 if (!bc.next()) return false; 00199 byte[] data = bc.getValBuf(); 00200 int acnt = TempTableMerge.getCount(data, 0); 00201 int bcnt = TempTableMerge.getCount(data, 1); 00202 duplicateCount = 00203 all 00204 ? Math.min(acnt, bcnt) 00205 : (acnt > 0 && bcnt > 0) ? 1 : 0; 00206 if (duplicateCount-- > 0) { 00207 tempTable.getRow(data, row); 00208 found = true; 00209 } 00210 } while (!found); 00211 return found; 00212 } 00213 return true; 00214 } 00215 00216 boolean nextExcept() throws SQLException, IOException { 00217 if (!all || duplicateCount-- <= 0) { 00218 boolean found = false; 00219 do { 00220 if (!bc.next()) return false; 00221 byte[] data = bc.getValBuf(); 00222 int acnt = TempTableMerge.getCount(data, 0); 00223 int bcnt = TempTableMerge.getCount(data, 1); 00224 duplicateCount = 00225 all 00226 ? (acnt - bcnt) 00227 : (acnt > 0 && bcnt == 0) ? 1 : 0; 00228 if (duplicateCount-- > 0) { 00229 tempTable.getRow(data, row); 00230 found = true; 00231 } 00232 } while (!found); 00233 return found; 00234 } 00235 return true; 00236 } 00237 00238 /** 00239 * On close, we release the resources. 00240 */ 00241 public void close() throws SQLException { 00242 try { 00243 if (bc != null) bc.release(); 00244 } finally { 00245 bc = null; 00246 try { 00247 if (tempTable != null) tempTable.release(); 00248 } catch (IOException e2) { 00249 throw DbException.wrapThrowable(e2); 00250 } finally { 00251 tempTable = null; 00252 } 00253 } 00254 } 00255 }