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.ArrayList ; 47 import java.util.HashMap ; 48 import java.util.Iterator ; 49 import java.util.Vector ; 50 51 import java.sql.SQLException ; 52 53 import antlr.RecognitionException; 54 55 import com.quadcap.sql.types.Op; 56 57 import com.quadcap.util.Debug; 58 59 64 public class JoinedTable extends TableExpression implements Externalizable { 65 int op = -1; 66 TableExpression a = null; 67 TableExpression b = null; 68 Tuple tuple = null; 69 Expression onExpression = null; 70 71 Vector usingList = null; 72 73 76 public JoinedTable() {} 77 78 81 public JoinedTable(int op, TableExpression a, TableExpression b) { 82 this.op = op; 83 this.a = a; 84 this.b = b; 85 } 86 87 90 public void setOnExpression(Expression on) { 91 this.onExpression = on; 92 } 93 94 97 public void setUsingList(Vector usingList) { 98 this.usingList = usingList; 99 } 100 101 102 106 122 public void checkSyntax() throws RecognitionException { 123 if ((op & Op.NATURAL) != 0) { 124 if (usingList != null) { 125 throw new RecognitionException("Can't specify both NATURAL and " + 126 "USING"); 127 } 128 if (onExpression != null) { 129 throw new RecognitionException("Can't specify both NATURAL and ON"); 130 } 131 } else if (op == Op.LEFT || op == Op.RIGHT || 132 op == Op.FULL || op == Op.INNER) { 133 if (usingList == null && onExpression == null) { 134 throw new RecognitionException(Op.toString(op) + 135 " join requires ON or USING " + 136 "clause"); 137 } 138 } else if (op == Op.UNION) { 139 if (usingList != null) { 140 throw new RecognitionException("Can't specify both UNION and USING"); 141 } 142 if (onExpression != null) { 143 throw new RecognitionException("Can't specify both UNION and ON"); 144 } 145 } 146 } 147 148 151 public void setWhere(Expression where) { 152 this.where = where; 153 a.setWhere(where); 154 b.setWhere(where); 155 } 156 157 public int rank() { return 2; } 158 159 public boolean isUpdatable() { return false; } 160 161 public void getBaseTables(Vector v) { 162 a.getBaseTables(v); 163 b.getBaseTables(v); 164 } 165 166 public void visitSubExpressions(ExpressionVisitor ev) { 167 if (a != null) ev.visit(a); 168 if (b != null) ev.visit(b); 169 } 170 171 String toString(Iterator iter) { 172 StringBuffer sb = new StringBuffer (); 173 while (iter.hasNext()) { 174 if (sb.length() > 0) sb.append(", "); 175 sb.append(iter.next().toString()); 176 } 177 return sb.toString(); 178 } 179 180 static String isa(Object x) { 181 return x == null ? "null" : 182 x.getClass().getName() + ":" + x; 183 } 184 185 public Cursor getCursor(Session session, Cursor outer) 186 throws SQLException 187 { 188 int nop = op & ~Op.NATURAL; 189 int[] map = null; 190 191 Cursor ra = a.getCursor(session, outer); 192 Cursor rb = b.getCursor(session, outer); 193 194 int size = ra.getColumnCount() + rb.getColumnCount(); 195 196 if ((op & Op.NATURAL) != 0) { 197 getNaturalJoinColumns(ra, rb); 198 } 199 200 int usize = usingList == null ? 0 : usingList.size(); 201 map = new int[size - usize]; 202 Tuple jtl = mapColumns(ra, rb, map, true); 203 JoinMapRow jrl = new JoinMapRow(map); 204 205 map = new int[size - usize]; 206 Tuple jtr = mapColumns(ra, rb, map, false); 207 JoinMapRow jrr = new JoinMapRow(map); 208 209 210 Cursor ret = null; 211 Cursor left = null; 212 Cursor right = null; 213 if (onExpression != null) { 214 where = new BinaryExpression(Op.AND, where, onExpression); 215 } 216 217 switch (nop) { 218 case Op.CROSS: 219 case Op.INNER: 220 ret = getCrossCursor(session, outer, 221 ra, rb, where, jtl, jrl, 222 false , 223 true ); 224 break; 225 case Op.LEFT: 226 ret = getCrossCursor(session, outer, 227 ra, rb, where, jtl, jrl, 228 true , 229 true ); 230 break; 231 case Op.RIGHT: 232 ret = getCrossCursor(session, outer, 233 rb, ra, where, jtr, jrr, 234 true , 235 true ); 236 break; 237 case Op.FULL: 238 left = getCrossCursor(session, outer, 239 ra, rb, where, jtl, jrl, 240 true , 241 true ); 242 right = getCrossCursor(session, outer, 243 rb, ra, where, jtr, jrr, 244 true , 245 false ); 246 break; 247 case Op.UNION: 248 ret = new JoinUnionCursor(session, outer, ra, rb, where, jtl, jrl); 249 break; 250 default: 251 throw new SQLException ("Bad join type: " + nop); 252 } 253 if (left != null && right != null) { 254 MultiCursor mc = new MultiCursor(session, left); 255 mc.appendCursor(session, right); 256 ret = mc; 257 } 258 if (ret == null) { 259 throw new SQLException ("Bad join"); 260 } 261 return ret; 262 } 263 264 Cursor getCrossCursor(Session session, Cursor outer, Cursor ca, Cursor cb, 265 Expression where, Tuple jt, JoinMapRow jrl, 266 boolean left, boolean inner) 267 throws SQLException 268 { 269 int[][] cols = 270 usingList != null ? getUsingColumns(ca, cb) : 271 new Analyze(session, where).getJoinColumns(ca, cb); 272 273 Cursor ret = null; 274 if (cols == null) { 275 ret = new JoinCrossCursor(session, outer, ca, cb, where, jt, jrl, 277 left, inner); 278 } else { 279 int[] aCols = cols[0]; 281 int[] bCols = cols[1]; 282 ret = new JoinInnerCursor(session, outer, ca, aCols, cb, bCols, 283 where, jt, jrl, left, inner); 284 } 285 return ret; 286 } 287 288 int[][] getUsingColumns(Tuple a, Tuple b) throws SQLException { 289 int[][] ret = null; 290 if (usingList != null) { 291 int len = usingList.size(); 292 ret = new int[2][len]; 293 for (int i = 0; i < len; i++) { 294 String u = usingList.get(i).toString(); 295 Column ca = a.getColumn(u); 296 Column cb = b.getColumn(u); 297 ret[0][i] = ca.getColumn(); 298 ret[1][i] = cb.getColumn(); 299 } 300 } 301 return ret; 302 } 303 304 void getNaturalJoinColumns(Tuple ta, Tuple tb) throws SQLException { 305 usingList = new Vector (); 306 HashMap t = new HashMap (); 307 for (int i = 1; i <= tb.getColumnCount(); i++) { 308 Column cb = tb.getColumn(i); 309 t.put(cb.getShortName(), cb); 310 } 311 for (int i = 1; i <= ta.getColumnCount(); i++) { 312 Column ca = ta.getColumn(i); 313 if (t.containsKey(ca.getShortName())) { 314 usingList.addElement(ca.getShortName()); 315 } 316 } 317 } 318 319 322 private final Tuple mapColumns(Tuple ra, Tuple rb, int[] map, boolean left) 323 throws SQLException 324 { 325 HashMap uMap = null; 326 TupleImpl ti = new TupleImpl(); 327 int usize = usingList == null ? 0 : usingList.size(); 328 329 if (usize > 0) { 331 Tuple outer = left ? ra : rb; 332 uMap = new HashMap (); 333 int[] umap = outer.mapColumns(usingList); 334 for (int i = 0; i < umap.length; i++) { 335 int u = umap[i]; 336 Column ci = outer.getColumn(u); 337 uMap.put(ci.getShortName(), ""); 338 Column col = new Column(ci.getShortName(), ci); 339 col.setJoinColumn(true); 340 ti.addColumn(col); 341 map[i] = 0-u; 342 } 343 } 344 345 int base = usize; 347 for (int i = 1; i <= ra.getColumnCount(); i++) { 348 Column ci = ra.getColumn(i); 349 if (uMap == null || !uMap.containsKey(ci.getShortName())) { 350 int c = ci.getColumn(); 351 if (map[base] == 0) { 352 map[base++] = left ? 0 - c : c; 353 ti.addColumn(ci.getName(), ci.getType()); 354 } 355 } 356 } 357 358 for (int i = 1; i <= rb.getColumnCount(); i++) { 360 Column ci = rb.getColumn(i); 361 if (uMap == null || !uMap.containsKey(ci.getShortName())) { 362 int c = ci.getColumn(); 363 if (map[base] == 0) { 364 map[base++] = left ? c : 0 - c; 365 ti.addColumn(ci.getName(), ci.getType()); 366 } 367 } 368 } 369 return ti; 370 } 371 372 public void readExternal(ObjectInput in) 373 throws IOException , ClassNotFoundException 374 { 375 this.op = in.readInt(); 376 this.a = (TableExpression)in.readObject(); 377 this.b = (TableExpression)in.readObject(); 378 this.onExpression = (Expression)in.readObject(); 379 this.usingList = (Vector )in.readObject(); 380 } 381 382 public void writeExternal(ObjectOutput out) throws IOException { 383 out.writeInt(op); 384 out.writeObject(a); 385 out.writeObject(b); 386 out.writeObject(onExpression); 387 out.writeObject(usingList); 388 } 389 390 public String toString() { 391 StringBuffer sb = new StringBuffer (a.toString()); 392 393 if ((op & Op.NATURAL) != 0) sb.append(" NATURAL"); 394 op &= ~Op.NATURAL; 395 sb.append(' '); 396 sb.append(Op.toString(op)); 397 sb.append(" JOIN "); 398 sb.append(b.toString()); 399 return sb.toString(); 400 } 401 402 public String name() { 404 StringBuffer sb = new StringBuffer ('('); 405 sb.append(a.name()); 406 sb.append("\n "); 407 sb.append(Op.toString(op)); 408 sb.append("\n"); 409 sb.append(b.name()); 410 sb.append(')'); 411 return sb.toString(); 412 } 413 } 415 | Popular Tags |