1 package com.quadcap.sql; 2 3 40 41 import java.io.Externalizable ; 42 import java.io.IOException ; 43 import java.io.ObjectInput ; 44 import java.io.ObjectOutput ; 45 46 import java.util.Enumeration ; 47 import java.util.Vector ; 48 49 import java.sql.SQLException ; 50 51 import com.quadcap.sql.index.Btree; 52 53 import com.quadcap.sql.types.Op; 54 import com.quadcap.sql.types.Type; 55 import com.quadcap.sql.types.TypeBoolean; 56 import com.quadcap.sql.types.Value; 57 import com.quadcap.sql.types.ValueBoolean; 58 59 import com.quadcap.util.Debug; 60 import com.quadcap.util.Util; 61 62 67 public class InExpression extends Expression implements Externalizable { 68 Expression e = null; 69 Expression f = null; 70 boolean not = false; 71 72 75 class InSessionState implements StatementContext { 76 boolean correlatedSubquery = true; 77 Session session; 78 Btree index = null; 79 byte[] aByte = new byte[1]; 80 81 84 public InSessionState(Session session) { 85 this.session = session; 86 } 87 88 public boolean initialized() { 89 return index != null; 90 } 91 92 95 void init(Expression f, Cursor cursor) throws SQLException { 96 Cursor d = f.getCursor(session, null); 101 try { 102 d.beforeFirst(); 103 d.next(); 104 Type eType = e.getType(session, cursor); 105 Type fType = d.getColumn(1).getType(); 106 if (eType.toString().equals(fType.toString())) { 107 correlatedSubquery = false; 108 } else { 109 correlatedSubquery = true; 114 } 115 } catch (Throwable t) { 116 correlatedSubquery = true; 117 } finally { 118 d.close(); 119 } 120 if (!correlatedSubquery) { 121 Cursor c = f.getCursor(session, cursor); 122 try { 123 this.index = session.makeTempTree(); 124 c.beforeFirst(); 125 if (c.getColumnCount() != 1) { 126 throw new SQLException ("'IN' comparator: Rank mismatch", 127 "42000"); 128 } 129 while (c.next()) { 130 Row fcrow = c.getRow(); 131 Value fval = fcrow.item(1); 132 if (!Value.isNull(fval)) { 133 byte[] key = Value.bytes(fval); 134 index.set(key, key.length, aByte, 0, 1); 135 } 136 } 137 } catch (IOException ex) { 138 throw DbException.wrapThrowable(ex); 139 } finally { 140 c.close(); 141 } 142 } 143 } 144 145 148 void init(Row r) throws SQLException { 149 try { 150 this.index = session.makeTempTree(); 151 for (int i = 1; i <= r.size(); i++) { 152 Value fval = r.item(i); 153 byte[] key = Value.bytes(fval); 154 index.set(key, key.length, aByte, 0, 1); 155 } 156 } catch (IOException ex) { 157 throw DbException.wrapThrowable(ex); 158 } 159 } 160 161 162 public int priority() { return 4; } 163 164 165 public void finish(boolean abort) throws IOException { 166 try { 167 if (index != null) { 168 index.free(); 169 } 170 } finally { 171 if (index != null) session.getDatabase().releaseTempFile(); 172 index = null; 173 } 174 } 175 176 177 public void reset() throws IOException { 178 finish(false); 179 } 180 181 182 public boolean contains(Value eval, Expression f, Cursor cursor) throws SQLException { 183 if (!correlatedSubquery) { 184 byte[] ekey = Value.bytes(eval); 185 try { 186 return index.get(ekey, ekey.length, aByte) != -1; 187 } catch (IOException ex) { 188 throw DbException.wrapThrowable(ex); 189 } 190 } else { 191 return matchCorrelated(f, cursor, eval); 192 } 193 } 194 195 196 boolean matchCorrelated(Expression f, Cursor cursor, Value eval) 197 throws SQLException 198 { 199 boolean match = false; 200 Cursor c = f.getCursor(session, cursor); 201 try { 202 c.beforeFirst(); 203 if (c.getColumnCount() != 1) { 204 throw new SQLException ("'IN' comparator: Rank mismatch", 205 "42000"); 206 } 207 while (!match && c.next()) { 208 Row fcrow = c.getRow(); 209 Value fval = fcrow.item(1); 210 match = Value.boolOp(Op.EQ, eval, fval); 211 } 212 } finally { 213 c.close(); 214 } 215 return match; 216 } 217 218 } 219 220 private InSessionState getSessionState(Session session) { 221 InSessionState s = (InSessionState)session.getContext(this, false); 222 if (s == null) { 223 s = new InSessionState(session); 224 session.putContext(this, false, s); 225 } 226 return s; 227 } 228 229 232 public InExpression() {} 233 234 237 public InExpression(Expression e, Expression f) { 238 this.e = e; 239 this.f = f; 240 } 241 242 245 public int rank() { return 0; } 246 247 250 public Type getType(Session session, Cursor cursor) { 251 return TypeBoolean.typeBoolean; 252 } 253 254 257 public Value getValue(Session session, Cursor cursor) throws SQLException { 258 switch (e.rank()) { 259 case 0: 260 return getValue1(session, cursor); 261 case 1: 262 return getValue2(session, cursor); 263 default: 264 throw new SQLException ("bad rank (" + e.rank() + 265 ") for left argument to IN", "42000"); 266 } 267 } 268 269 private Value getValue1(Session session, Cursor cursor) 270 throws SQLException 271 { 272 Value eval = e.getValue(session, cursor); 273 boolean match = false; 274 switch (f.rank()) { 275 case 0: 276 throw new SQLException ("'IN' comparator: Rank mismatch", "42000"); 277 case 1: 278 Row frow = f.getValues(session, cursor); 279 for (int i = 1; !match && i <= frow.size(); i++) { 280 Value fval = frow.item(i); 281 match = Value.boolOp(Op.EQ, eval, fval); 282 } 283 break; 284 case 2: 285 InSessionState s = getSessionState(session); 286 if (!s.initialized()) { 287 s.init(f, cursor); 288 } 289 match = s.contains(eval, f, cursor); 290 break; 291 default: 292 throw new SQLException ("internal error, bad rank: " + f.rank(), 293 "Q0004"); 294 } 295 match ^= not; 296 return new ValueBoolean(match); 297 } 298 299 300 private Value getValue2(Session session, Cursor cursor) 301 throws SQLException 302 { 303 Row erow = e.getValues(session, cursor); 304 boolean match = false; 305 switch (f.rank()) { 306 case 0: 307 case 1: 308 throw new SQLException ("'IN' comparator: Rank mismatch", "42000"); 309 case 2: 310 Cursor c = f.getCursor(session, cursor); 311 try { 312 if (c.getColumnCount() != cursor.getColumnCount()) { 313 throw new SQLException ("'IN' comparator: Rank mismatch", 314 "42000"); 315 } 316 while (!match && c.next()) { 317 Row frow = c.getRow(); 318 match = matchRow(erow, frow); 319 } 320 } finally { 321 c.close(); 322 } 323 break; 324 default: 325 throw new SQLException ("internal error, bad rank: " + f.rank(), 326 "Q0005"); 327 } 328 match ^= not; 329 return new ValueBoolean(match); 330 } 331 332 static boolean matchRow(Row erow, Row frow) throws SQLException { 333 boolean match = true; 334 for (int i = 1; match && i <= erow.size(); i++) { 335 match = Value.boolOp(Op.EQ, erow.item(i), frow.item(i)); 336 } 337 return match; 338 } 339 340 public void invert() { 341 not = !not; 342 } 343 344 public String toString() { 345 String n = not ? "not " : ""; 346 return "(" + n + e + " IN " + f + ")"; 347 } 348 349 public Expression getLhs() { return e; } 350 351 public void visitSubExpressions(ExpressionVisitor ev) { 352 ev.visit(e); 353 ev.visit(f); 354 } 355 356 public void readExternal(ObjectInput in) 357 throws IOException , ClassNotFoundException 358 { 359 e = (Expression)in.readObject(); 360 f = (Expression)in.readObject(); 361 not = (in.read() == 1); 362 } 363 364 public void writeExternal(ObjectOutput out) throws IOException { 365 out.writeObject(e); 366 out.writeObject(f); 367 out.write(not ? 1 : 0); 368 } 369 } 370 | Popular Tags |