00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
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
00067
00068
00069
00070
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
00169
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
00179
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
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 }