// assumes input data fall within capacity of list private void updateNodeList(PositionNode node, int finalPos, List<QueryModelNode> list) { int initialPos = node.getPosition(); QueryModelNode qNode = list.remove(initialPos); if (finalPos < list.size()) { list.add(finalPos, qNode); } else { list.add(qNode); } }
// assumes g.l.b <= l.u.b. // iterates through pcj nodes in query from lowest position to // highest looking for a difference in index position greater than // one. Given the leftmost pair of nodes separated by two or more // spaces, the leftmost node in the pair is moved so that its final // position is one position to the left of the rightmost node. For // example, given nodes at index 1 and index 3, the node at index 1 // is advanced to index 2. This method returns the suggested Move, // but does not actually perform the Move. private Move getNextMove() { Iterator<PositionNode> posIterator = pcjPosSet.iterator(); PositionNode current; if (posIterator.hasNext()) { current = posIterator.next(); } else { throw new IllegalStateException("PCJ has no nodes!"); } PositionNode next; int pos1 = -1; int pos2 = -1; while (posIterator.hasNext()) { next = posIterator.next(); pos1 = current.getPosition(); pos2 = next.getPosition(); // move nodes are not adjacent if (pos1 + 1 < pos2) { if (leastUpperBound > pos2) { return new Move(current, pos2 - 1); } // pos1 < leastUpperBound < pos2 b/c pos1 < leastUpperBound by // design else if (greatestLowerBound < pos1) { return new Move(next, pos1 + 1); } // move current to node after greatestLowerBound else { return new Move(current, greatestLowerBound); } } current = next; } return new Move(); }
// updates nodes in given TreeSet between node.getPosition() and position private void updatePositionNodeSet(PositionNode node, int position, TreeSet<PositionNode> set) { if (set.size() == 0) { return; } int oldPos = node.getPosition(); int diff = position - oldPos; SortedSet<PositionNode> posNodes; boolean containsNode = false; if (diff == 0) { return; } // remove node before decrementing or incrementing to prevent overwriting if (set.contains(node)) { containsNode = true; set.remove(node); } if (diff > 0) { posNodes = set.subSet(node, false, new PositionNode(position), true); List<PositionNode> pNodeList = new ArrayList<>(); for (PositionNode pos : posNodes) { pNodeList.add(pos); } // decrement posNodes for (PositionNode pos : pNodeList) { int p = pos.getPosition() - 1; updatePositionNode(pos, p, set); } } else { posNodes = set.subSet(new PositionNode(position), true, node, false); // create list to iterate in reverse order List<PositionNode> pNodeList = new ArrayList<>(); for (PositionNode pos : posNodes) { pNodeList.add(pos); } // increment elements of TreeSet in reverse order so // that no collisions occur - PositionNodes are incremented // into slot created by removing node for (int i = pNodeList.size() - 1; i >= 0; i--) { PositionNode pNode = pNodeList.get(i); int p = pNode.getPosition() + 1; updatePositionNode(pNode, p, set); } } if (containsNode) { node.setPosition(position); set.add(node); } }
// adds bound to either lowerBoundSet or uppderBoundSet, depending on initial and // final position of move private void addBound(PositionNode bound, PositionNode node, int finalPos) { int diff = finalPos - node.getPosition(); if (diff == 0) { return; } if (diff > 0) { if (upperBoundSet.contains(bound)) { return; } else { upperBoundSet.add(bound); } } else { if (lowerBoundSet.contains(bound)) { return; } else { lowerBoundSet.add(bound); } } }
// determine if given node can be moved to finalPos // assumes node.position and finalPos fall within index range of list private PositionNode getBounds( PositionNode node, int finalPos, List<QueryModelNode> list, TreeSet<PositionNode> leftJoinNodes) { // filters can be moved up and pushed down join segment // without affecting bound and unbound variables of // FlattenedOptionals -- Filters can be pushed down as // far as possible because it is assumed that any variable // that appears in a Filter also appears in a PCJ node // if Filters can be grouped, then Filter variables will // automatically be bound if (node.getNode() instanceof ValueExpr) { return new PositionNode(); } int diff = finalPos - node.getPosition(); if (diff == 0) { return new PositionNode(); } if (node.isOptional) { FlattenedOptional optional = ((FlattenedOptional) node.getNode()).clone(); if (diff < 0) { for (int i = node.getPosition() - 1; i > finalPos - 1; i--) { QueryModelNode tempNode = list.get(i); if (tempNode instanceof ValueExpr) { continue; } if (!optional.canAddTuple((TupleExpr) tempNode)) { return new PositionNode(tempNode, i); } if (tempNode instanceof FlattenedOptional) { FlattenedOptional tempOptional = (FlattenedOptional) tempNode; if (!tempOptional.canRemoveTuple(optional)) { return new PositionNode(tempNode, i); } } optional.addArg((TupleExpr) tempNode); } } else { for (int i = node.getPosition() + 1; i < finalPos + 1; i++) { // TODO // check // bounds QueryModelNode tempNode = list.get(i); if (tempNode instanceof ValueExpr) { continue; } if (!optional.canRemoveTuple((TupleExpr) tempNode)) { return new PositionNode(tempNode, i); } if (tempNode instanceof FlattenedOptional) { FlattenedOptional tempOptional = (FlattenedOptional) tempNode; if (!tempOptional.canAddTuple(optional)) { return new PositionNode(tempNode, i); } } optional.removeArg((TupleExpr) tempNode); } } return new PositionNode(); } else { TupleExpr te = (TupleExpr) node.getNode(); SortedSet<PositionNode> leftJoins; if (diff < 0) { leftJoins = leftJoinNodes.subSet(new PositionNode(finalPos), true, node, false); for (PositionNode pNode : leftJoins) { FlattenedOptional optional = (FlattenedOptional) pNode.getNode(); if (!optional.canRemoveTuple(te)) { return new PositionNode(pNode); } } } else { leftJoins = leftJoinNodes.subSet(node, false, new PositionNode(finalPos), true); for (PositionNode pNode : leftJoins) { FlattenedOptional optional = (FlattenedOptional) pNode.getNode(); if (!optional.canAddTuple(te)) { return new PositionNode(pNode); } } } return new PositionNode(); } }
// works only if moving node to final position does not move it across // another node in set private void updatePositionNode(PositionNode node, int position, TreeSet<PositionNode> set) { set.remove(node); node.setPosition(position); set.add(node); }
// updates the var counts in specified left join index private void updateLeftJoinNodes(PositionNode node, int finalPos) { if (node.getNode() instanceof ValueExpr) { return; } int diff = finalPos - node.getPosition(); if (diff == 0) { return; } if (node.isOptional) { leftJoinPosSet.remove(node); FlattenedOptional optional = (FlattenedOptional) node.getNode(); if (diff < 0) { for (int i = node.getPosition() - 1; i > finalPos - 1; i--) { QueryModelNode tempNode = queryNodes.get(i); if (tempNode instanceof ValueExpr) { continue; } optional.addArg((TupleExpr) tempNode); } } else { for (int i = node.getPosition() + 1; i < finalPos + 1; i++) { QueryModelNode tempNode = queryNodes.get(i); if (tempNode instanceof ValueExpr) { continue; } optional.removeArg((TupleExpr) tempNode); } } node.setNode(optional); // FlattenedOptional equals does not take into account var counts // The following three lines update the var count in the optional in list int index = queryNodes.indexOf(optional); queryNodes.remove(optional); queryNodes.add(index, optional); leftJoinPosSet.add(node); } else { TupleExpr te = (TupleExpr) node.getNode(); SortedSet<PositionNode> optionals; if (diff < 0) { optionals = leftJoinPosSet.subSet(new PositionNode(finalPos), true, node, false); for (PositionNode pNode : optionals) { FlattenedOptional optional = (FlattenedOptional) pNode.getNode(); optional.removeArg(te); } } else { optionals = leftJoinPosSet.subSet(node, false, new PositionNode(finalPos), true); for (PositionNode pNode : optionals) { FlattenedOptional optional = (FlattenedOptional) pNode.getNode(); optional.addArg(te); } } } }