|
3 | 3 | import parser.SelectStatement;
|
4 | 4 | import storageManager.*;
|
5 | 5 |
|
6 |
| -import java.util.ArrayList; |
7 |
| -import java.util.Iterator; |
8 |
| -import java.util.LinkedHashSet; |
9 |
| -import java.util.Set; |
| 6 | +import java.util.*; |
10 | 7 |
|
11 | 8 | public class SelectProc extends Procedures {
|
12 | 9 | public SelectProc(MainMemory mem, Disk disk, SchemaManager schema_manager) {
|
@@ -185,22 +182,178 @@ public ArrayList<Tuple> selectTuples(SelectStatement stmt) {
|
185 | 182 | schema_manager.deleteRelation("tempSelect");
|
186 | 183 | }
|
187 | 184 |
|
188 |
| - // Checking DISTINCT clause |
189 |
| - if (stmt.isHasDistinct()) { |
190 |
| -// System.out.println("In DISTINCT clause "); |
191 |
| - Set<Tuple> hs = new LinkedHashSet<>(); |
192 |
| - hs.addAll(result); |
193 |
| -// System.out.println(hs); |
194 |
| - result.clear(); |
195 |
| - result.addAll(hs); |
196 |
| - } |
197 | 185 | } else { // Multiple Table queries
|
198 | 186 |
|
| 187 | + // Create temporary schema and relation to store the combined tuple with fields from all relations |
| 188 | + ArrayList<String> temp_Fnames = new ArrayList<String>(); |
| 189 | + ArrayList<FieldType> temp_Ftypes = new ArrayList<FieldType>(); |
| 190 | + Schema join_schema = null; |
| 191 | + |
| 192 | + stmt.getTables().forEach(rel -> { |
| 193 | + Schema schema = schema_manager.getRelation(rel).getSchema(); |
| 194 | + schema.getFieldNames().forEach(fname -> { |
| 195 | + temp_Fnames.add(rel +"." + fname); |
| 196 | + temp_Ftypes.add(schema.getFieldType(fname)); |
| 197 | + }); |
| 198 | + }); |
| 199 | + |
| 200 | + if (!temp_Fnames.isEmpty()) { |
| 201 | + join_schema = new Schema(temp_Fnames, temp_Ftypes); |
| 202 | + } |
| 203 | + Relation join_relation = schema_manager.createRelation("joinSelect", join_schema); |
| 204 | + |
| 205 | + |
| 206 | + // Check for Order By clause. If present, sort the given relation and then apply cross product with other |
| 207 | + // relations. Always use this relation or its result in Outer loop so as to maintain the sorted order. |
| 208 | + if (!(orderCol == null || orderCol.isEmpty())) { |
| 209 | + int idx = orderCol.lastIndexOf('.'); |
| 210 | + if (idx != -1) { |
| 211 | + String orderRelName = orderCol.substring(0, idx); |
| 212 | + List<String> names = stmt.getTables(); |
| 213 | + // put the order relation name at first |
| 214 | + names.remove(orderRelName); |
| 215 | + names.add(0, orderRelName); |
| 216 | + stmt.setTables(names); |
| 217 | + // get the sorted tuples |
| 218 | + result = OrderClause.sortRelation(schema_manager.getRelation(orderRelName), |
| 219 | + orderCol.substring(idx + 1), mem, disk, schema_manager); |
| 220 | + // eliminate duplicates if required so as to reduce time taken by cross join |
| 221 | + if (stmt.isHasDistinct()) { |
| 222 | + Set<Tuple> hs = new LinkedHashSet<>(); |
| 223 | + hs.addAll(result); |
| 224 | + result.clear(); |
| 225 | + result.addAll(hs); |
| 226 | + } |
| 227 | + result = crossProduct(join_relation, orderRelName, result, stmt.getTables().get(1), |
| 228 | + loadTuples(stmt.getTables().get(1), stmt.isHasDistinct())); |
| 229 | + } else { |
| 230 | + throw new RuntimeException("Relation name not specified in OrderBy clause"); |
| 231 | + } |
| 232 | + } else { |
| 233 | + result = crossProduct(join_relation, |
| 234 | + stmt.getTables().get(0), loadTuples(stmt.getTables().get(0), stmt.isHasDistinct()), |
| 235 | + stmt.getTables().get(1), loadTuples(stmt.getTables().get(1), stmt.isHasDistinct())); |
| 236 | + } |
| 237 | + for(int i=2; i<stmt.getTables().size(); i++) { |
| 238 | + ArrayList<Tuple> loadedTuples = loadTuples(stmt.getTables().get(i), stmt.isHasDistinct()); |
| 239 | + result = crossProduct(join_relation, null, result, stmt.getTables().get(i), loadedTuples); |
| 240 | + } |
| 241 | + |
| 242 | + // Check for where clause. Eliminate tuple not confirming Where clause, if any |
| 243 | + if (clause != null) { |
| 244 | + Iterator<Tuple> iter = result.iterator(); |
| 245 | + while (iter.hasNext()) { |
| 246 | + Tuple tup = iter.next(); |
| 247 | + if (!WhereClause.evaluatePostfix(clause, tup)) |
| 248 | + iter.remove(); |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + // Projection |
| 253 | + if (!"*".equals(stmt.getColumns().get(0))) { |
| 254 | + ArrayList<String> tmp_Fnames = new ArrayList<String>(); |
| 255 | + ArrayList<FieldType> tmp_Ftypes = new ArrayList<FieldType>(); |
| 256 | + Schema tmp_schema = null; |
| 257 | + |
| 258 | + Schema finalJoin_schema = join_schema; |
| 259 | + stmt.getColumns().forEach(s -> { |
| 260 | + if (s.lastIndexOf('.') == -1){ |
| 261 | + throw new RuntimeException("Relation name NOT specified for column " + s); |
| 262 | + } else if (!finalJoin_schema.fieldNameExists(s)) { |
| 263 | + throw new RuntimeException("No such field " + s + " exists "); |
| 264 | + } |
| 265 | + tmp_Fnames.add(s); |
| 266 | + tmp_Ftypes.add(finalJoin_schema.getFieldType(s)); |
| 267 | + }); |
| 268 | + |
| 269 | + if (!tmp_Fnames.isEmpty()) { |
| 270 | + tmp_schema = new Schema(tmp_Fnames, tmp_Ftypes); |
| 271 | + } |
| 272 | + Relation tmp_relation = schema_manager.createRelation("tmpSelect", tmp_schema); |
| 273 | + |
| 274 | + ArrayList<Tuple> tmpResult = result; |
| 275 | + result = new ArrayList<>(); |
| 276 | + ArrayList<Tuple> finalResult2 = result; |
| 277 | + tmpResult.forEach(tuple -> { |
| 278 | + Tuple tmp_Tuple = tmp_relation.createTuple(); |
| 279 | + stmt.getColumns().forEach(s -> { |
| 280 | + if (finalJoin_schema.getFieldType(s) == FieldType.INT) { |
| 281 | + tmp_Tuple.setField(s, tuple.getField(s).integer); |
| 282 | + } else { |
| 283 | + tmp_Tuple.setField(s, tuple.getField(s).str); |
| 284 | + } |
| 285 | + }); |
| 286 | + finalResult2.add(tmp_Tuple); |
| 287 | + }); |
| 288 | + |
| 289 | + // Delete temporary relation |
| 290 | + schema_manager.deleteRelation("tmpSelect"); |
| 291 | + } |
| 292 | + |
| 293 | + // Delete Temporary Table |
| 294 | + schema_manager.deleteRelation("joinSelect"); |
199 | 295 | }
|
200 | 296 |
|
| 297 | + // Check for eliminating duplicates |
| 298 | + if (stmt.isHasDistinct()) { |
| 299 | + Set<Tuple> hs = new LinkedHashSet<>(); |
| 300 | + hs.addAll(result); |
| 301 | + result.clear(); |
| 302 | + result.addAll(hs); |
| 303 | + } |
201 | 304 |
|
202 | 305 | System.out.println("Select Procedure Result size \n" + result.size());
|
203 | 306 | System.out.println("Select Procedure Result \n" + result.toString());
|
204 | 307 | return result;
|
205 | 308 | }
|
| 309 | + |
| 310 | + public ArrayList<Tuple> crossProduct(Relation relation, String relationName1, ArrayList<Tuple> r1, |
| 311 | + String relationName2, ArrayList<Tuple> r2) { |
| 312 | + ArrayList<Tuple> result = new ArrayList<>(); |
| 313 | + Schema schema1 = r1.get(0).getSchema(); |
| 314 | + Schema schema2 = r2.get(0).getSchema(); |
| 315 | + |
| 316 | + r1.forEach(tup1 -> r2.forEach(tup2 -> { |
| 317 | + Tuple tuple = relation.createTuple(); |
| 318 | + schema1.getFieldNames().forEach(s -> { |
| 319 | + if (schema1.getFieldType(s) == FieldType.INT) { |
| 320 | + tuple.setField((relationName1 == null)? s: relationName1 + "." + s, tup1.getField(s).integer); |
| 321 | + } else { |
| 322 | + tuple.setField((relationName1 == null)? s: relationName1 + "." + s, tup1.getField(s).str); |
| 323 | + } |
| 324 | + }); |
| 325 | + schema2.getFieldNames().forEach(s -> { |
| 326 | + if (schema2.getFieldType(s) == FieldType.INT) { |
| 327 | + tuple.setField((relationName2 == null)? s: relationName2 + "." + s, tup2.getField(s).integer); |
| 328 | + } else { |
| 329 | + tuple.setField((relationName2 == null)? s: relationName2 + "." + s, tup2.getField(s).str); |
| 330 | + } |
| 331 | + }); |
| 332 | + result.add(tuple); |
| 333 | + })); |
| 334 | + return result; |
| 335 | + } |
| 336 | + |
| 337 | + public ArrayList<Tuple> loadTuples(String relationName, boolean distinct) { |
| 338 | + ArrayList<Tuple> result = new ArrayList<>(); |
| 339 | + Set<Tuple> hashSet = new LinkedHashSet<>(); |
| 340 | + Relation relation = schema_manager.getRelation(relationName); |
| 341 | + int blocksInRel = relation.getNumOfBlocks(); |
| 342 | + for (int i = 0; i < blocksInRel; i += mem.getMemorySize()) { |
| 343 | + // reading blocks from disk in accordance to memory capacity |
| 344 | + relation.getBlocks(i, 0, (blocksInRel - i >= mem.getMemorySize()) ? |
| 345 | + mem.getMemorySize() : blocksInRel - i); |
| 346 | + if (distinct) { |
| 347 | + hashSet.addAll(mem.getTuples(0, (blocksInRel - i >= mem.getMemorySize()) ? |
| 348 | + mem.getMemorySize() : blocksInRel - i)); |
| 349 | + } else { |
| 350 | + result.addAll(mem.getTuples(0, (blocksInRel - i >= mem.getMemorySize()) ? |
| 351 | + mem.getMemorySize() : blocksInRel - i)); |
| 352 | + } |
| 353 | + } |
| 354 | + if (distinct) { |
| 355 | + result.addAll(hashSet); |
| 356 | + } |
| 357 | + return result; |
| 358 | + } |
206 | 359 | }
|
0 commit comments