[Mulgara-svn] r254 - in trunk: data src/jar/resolver/java/org/mulgara/resolver src/jar/tuples/java/org/mulgara/store/tuples src/jar/util/java/org/mulgara/util
andrae at mulgara.org
andrae at mulgara.org
Thu Apr 26 06:06:17 UTC 2007
Author: andrae
Date: 2007-04-26 01:06:17 -0500 (Thu, 26 Apr 2007)
New Revision: 254
Added:
trunk/data/prefix-unbound.rdf
Modified:
trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/Assignment.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/LiteralTuples.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperationsUnitTest.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoin.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoinUnitTest.java
trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnorderedProjection.java
trunk/src/jar/util/java/org/mulgara/util/FileUtil.java
Log:
Fix for MGR-34 http://mulgara.org/jira/browse/MGR-34 merged from
branches/nuc-disj into trunk/
merge -r 209:253 https://mulgara.org/svn/mulgara/branches/nuc-disj
Copied: trunk/data/prefix-unbound.rdf (from rev 253, branches/nuc-disj/data/prefix-unbound.rdf)
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/AdvDatabaseSessionUnitTest.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -79,6 +79,7 @@
private static final URI model2URI;
private static final URI model3URI;
private static final URI model4URI;
+ private static final URI model5URI;
static {
try {
@@ -88,6 +89,7 @@
model2URI = new URI("local:database#model2");
model3URI = new URI("local:database#model3");
model4URI = new URI("local:database#model4");
+ model5URI = new URI("local:database#model5");
} catch (URISyntaxException e) {
throw new Error("Bad hardcoded URI", e);
}
@@ -114,6 +116,7 @@
suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitRollbackIsolationQuery"));
suite.addTest(new AdvDatabaseSessionUnitTest("testExplicitCommitIsolationQuery"));
suite.addTest(new AdvDatabaseSessionUnitTest("testImplicitCommitQuery"));
+ suite.addTest(new AdvDatabaseSessionUnitTest("testPrefixingWithUnbound"));
suite.addTest(new AdvDatabaseSessionUnitTest("testDatabaseDelete"));
return suite;
@@ -1105,7 +1108,7 @@
assertFalse(answer.next());
answer.close();
- session1.removeModel(model3URI);
+ session1.removeModel(model4URI);
} finally {
session2.close();
}
@@ -1118,6 +1121,86 @@
}
+ public void testPrefixingWithUnbound() throws URISyntaxException
+ {
+ logger.warn("testPrefixingWithUnbound");
+ URI fileURI = new File("data/prefix-unbound.rdf").toURI();
+
+ try {
+ Session session = database.newSession();
+ try {
+ session.createModel(model5URI, null);
+ session.setModel(model5URI, new ModelResource(fileURI));
+
+ Variable varA = new Variable("a");
+ Variable varB = new Variable("b");
+ Variable varT = new Variable("t");
+
+ List selectList = new ArrayList(2);
+ selectList.add(varA);
+ selectList.add(varT);
+
+ // Check data loaded
+ Answer answer = session.query(new Query(
+ selectList, // SELECT
+ new ModelResource(model5URI), // FROM
+ new ConstraintConjunction(Arrays.asList(
+ new ConstraintExpression[] {
+ new ConstraintImpl(varB,
+ new URIReferenceImpl(new URI("test:p01")),
+ new URIReferenceImpl(new URI("test:o01"))),
+ new ConstraintImpl(varB,
+ new URIReferenceImpl(new URI("test:p02")),
+ varA),
+ new ConstraintDisjunction(
+ new ConstraintConjunction(
+ new ConstraintImpl(varB,
+ new URIReferenceImpl(new URI("test:p03")),
+ new URIReferenceImpl(new URI("test:o03"))),
+ new ConstraintIs(varT,
+ new URIReferenceImpl(new URI("result:0")))),
+ new ConstraintIs(varT,
+ new URIReferenceImpl(new URI("result:1")))),
+ })), // WHERE
+ null, // HAVING
+ Arrays.asList(new Order[] { // ORDER BY
+ new Order(varA, true),
+ new Order(varT, true),
+ }),
+ null, // LIMIT
+ 0, // OFFSET
+ new UnconstrainedAnswer() // GIVEN
+ ));
+
+ String[][] results = {
+ { "test:o02", "result:0" },
+ { "test:o02", "result:1" },
+ { "test:o04", "result:0" },
+ { "test:o04", "result:1" },
+ };
+ answer.beforeFirst();
+ String s = "comparing results:\n" + answer.getVariables();
+ while (answer.next()) {
+ s += "\n[";
+ for (int i = 0; i < answer.getNumberOfVariables(); i++) {
+ s += " " + answer.getObject(i);
+ }
+ s += " ]";
+ }
+
+ compareResults(results, answer);
+ answer.close();
+
+ session.removeModel(model5URI);
+ } finally {
+ session.close();
+ }
+ } catch (Exception e) {
+ fail(e);
+ }
+ }
+
+
public void testDatabaseDelete() {
database.delete();
database = null;
@@ -1128,17 +1211,22 @@
//
private void compareResults(String[][] expected, Answer answer) throws Exception {
- answer.beforeFirst();
- for (int i = 0; i < expected.length; i++) {
- assertTrue("Answer short at row " + i, answer.next());
- assertEquals(expected[i].length, answer.getNumberOfVariables());
- for (int j = 0; j < expected[i].length; j++) {
- URIReferenceImpl uri = new URIReferenceImpl(
- new URI(expected[i][j]));
- assertEquals(uri, answer.getObject(j));
+ try {
+ answer.beforeFirst();
+ for (int i = 0; i < expected.length; i++) {
+ assertTrue("Answer short at row " + i, answer.next());
+ assertEquals(expected[i].length, answer.getNumberOfVariables());
+ for (int j = 0; j < expected[i].length; j++) {
+ URIReferenceImpl uri = new URIReferenceImpl(new URI(expected[i][j]));
+ assertEquals(uri, answer.getObject(j));
+ }
}
+ assertFalse(answer.next());
+ } catch (Exception e) {
+ logger.error("Failed test - " + answer);
+ answer.close();
+ throw e;
}
- assertFalse(answer.next());
}
private void compareResults(Answer answer1, Answer answer2) throws Exception {
Modified: trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java
===================================================================
--- trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/resolver/java/org/mulgara/resolver/MulgaraTransactionManager.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -408,8 +408,6 @@
logger.error("Attempt to suspend write transaction without setting AutoCommit Off");
throw new MulgaraTransactionException(
"Attempt to suspend write transaction without setting AutoCommit Off");
- } else {
-// logger.error("Suspended transaction: ac=" + autoCommit + " t=" + transaction + "ut=" + userTransaction);
}
Transaction xa = transactionManager.suspend();
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/Assignment.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/Assignment.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/Assignment.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -283,6 +283,10 @@
return new ArrayList(0);
}
+ public RowComparator getRowComparator() {
+ return DefaultRowComparator.getInstance();
+ }
+
/**
* METHOD TO DO
*
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/LiteralTuples.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/LiteralTuples.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/LiteralTuples.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -74,12 +74,23 @@
private int currentTuple;
private boolean[] columnContainsUnbound;
private long[] prefix;
+ private boolean sorted;
+ public LiteralTuples(String[] variableNames, boolean sorted) {
+ List vars = new ArrayList();
+ for (int i = 0; i < variableNames.length; i++) {
+ Variable v = new Variable(variableNames[i]);
+ assert!vars.contains(v);
+ vars.add(v);
+ }
+ init((Variable[]) vars.toArray(new Variable[0]), sorted);
+ }
+
/**
* Creates a literal tuples with specified variables.
*/
public LiteralTuples(Variable[] variables) {
- init(variables);
+ init(variables, false);
}
/**
@@ -87,22 +98,17 @@
* Variables created to match variableNames[].
*/
public LiteralTuples(String[] variableNames) {
- List vars = new ArrayList();
- for (int i = 0; i < variableNames.length; i++) {
- Variable v = new Variable(variableNames[i]);
- assert!vars.contains(v);
- vars.add(v);
- }
- init((Variable[]) vars.toArray(new Variable[0]));
+ this(variableNames, false);
}
- private void init(Variable[] variables) {
+ private void init(Variable[] variables, boolean sorted) {
tuples = new ArrayList();
currentTuple = 0;
tupleIterator = null;
setVariables(Arrays.asList(variables));
columnContainsUnbound = new boolean[variables.length];
Arrays.fill(columnContainsUnbound, false);
+ this.sorted = sorted;
}
/**
@@ -170,7 +176,11 @@
}
public RowComparator getComparator() {
- return null;
+ if (sorted) {
+ return DefaultRowComparator.getInstance();
+ } else {
+ return null;
+ }
}
//
@@ -223,7 +233,7 @@
}
public boolean hasNoDuplicates() throws TuplesException {
- return isUnconstrained();
+ return sorted || isUnconstrained();
}
public Object clone() {
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperations.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -204,7 +204,9 @@
while (i.hasNext()) {
Tuples operand = (Tuples)i.next();
Tuples proj = project(operand, variables);
- projected.add(proj);
+ Tuples sorted = sort(proj);
+ projected.add(sorted);
+ proj.close();
operand.close();
}
@@ -218,21 +220,6 @@
}
- private static String printArgs(String header, List args) {
- StringBuffer buff = new StringBuffer(header + "[");
- Iterator i = args.iterator();
- if (i.hasNext()) {
- buff.append(tuplesSummary((Tuples)i.next()));
- }
-
- while (i.hasNext()) {
- buff.append(", " + tuplesSummary((Tuples)i.next()));
- }
- buff.append("]");
- return buff.toString();
- }
-
-
/**
* This is approximately a conjunction.
*/
@@ -559,8 +546,11 @@
}
// Add all variables that don't contain UNBOUND to boundVars set.
- // Note that the inefficiency this introduces for distributed results
+ // Note: the inefficiency this introduces for distributed results
// can only be eliminated by propagating isColumnEverUnbound through Answer.
+ // Note: this is required to ensure that a subsequent operand will not
+ // rely on this variable when selecting an index as if it is UNBOUND in a
+ // left-operand it becomes unprefixed.
Variable[] vars = bestTuples.getVariables();
for (int i = 0; i < vars.length; i++) {
if (!bestTuples.isColumnEverUnbound(i)) {
@@ -986,6 +976,21 @@
}
+ private static String printArgs(String header, List args) {
+ StringBuffer buff = new StringBuffer(header + "[");
+ Iterator i = args.iterator();
+ if (i.hasNext()) {
+ buff.append(tuplesSummary((Tuples)i.next()));
+ }
+
+ while (i.hasNext()) {
+ buff.append(", " + tuplesSummary((Tuples)i.next()));
+ }
+ buff.append("]");
+ return buff.toString();
+ }
+
+
private static StringBuffer indentedTuplesTree(Tuples tuples, String indent) {
StringBuffer buff = new StringBuffer();
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperationsUnitTest.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperationsUnitTest.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/TuplesOperationsUnitTest.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -33,6 +33,9 @@
// Log4J
import org.apache.log4j.Logger;
+// Mulgara
+import org.mulgara.query.Variable;
+
/**
* Test case for {@link TuplesOperationsUnitTest}.
*
@@ -76,8 +79,11 @@
* @return The test suite
*/
public static Test suite() {
+ TestSuite suite = new TestSuite();
- return new TestSuite(TuplesOperationsUnitTest.class);
+ suite.addTest(new TuplesOperationsUnitTest("testReorderedAppend"));
+
+ return suite;
}
/**
@@ -99,8 +105,42 @@
*
* @throws Exception if query fails when it should have succeeded
*/
- public void testFoo() throws Exception {
+ public void testReorderedAppend() throws Exception {
+ LiteralTuples lhs = new LiteralTuples(new String[] {"x"}, true);
+ LiteralTuples rhs1 = new LiteralTuples(new String[] {"x", "y"}, true);
+ LiteralTuples rhs2 = new LiteralTuples(new String[] {"y", "x"}, true);
- // not yet implemented
+ lhs.appendTuple(new long[] { 1 });
+ lhs.appendTuple(new long[] { 6 });
+
+ rhs1.appendTuple(new long[] { 1, 2 });
+ rhs1.appendTuple(new long[] { 1, 3 });
+ rhs1.appendTuple(new long[] { 4, 1 });
+
+ rhs2.appendTuple(new long[] { 5, 1 });
+ rhs2.appendTuple(new long[] { 6, 1 });
+ rhs2.appendTuple(new long[] { 1, 7 });
+
+ Tuples append = TuplesOperations.append(rhs1, rhs2);
+ Tuples join = TuplesOperations.join(lhs, append);
+ append.close();
+
+ logger.warn("join - " + TuplesOperations.formatTuplesTree(join));
+
+ Variable[] vars = join.getVariables();
+ assertEquals(2, vars.length);
+ assertEquals(new Variable("x"), vars[0]);
+ assertEquals(new Variable("y"), vars[1]);
+
+ join.beforeFirst();
+
+ TuplesTestingUtil.testTuplesRow(join, new long[] { 1, 2 });
+ TuplesTestingUtil.testTuplesRow(join, new long[] { 1, 3 });
+ TuplesTestingUtil.testTuplesRow(join, new long[] { 1, 5 });
+ TuplesTestingUtil.testTuplesRow(join, new long[] { 1, 6 });
+
+ assertFalse(join.next());
+
+ TuplesTestingUtil.closeTuples(new Tuples[] { join });
}
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoin.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoin.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoin.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -16,7 +16,9 @@
* created by Plugged In Software Pty Ltd are Copyright (C) 2001,2002
* Plugged In Software Pty Ltd. All Rights Reserved.
*
- * Contributor(s): N/A.
+ * Contributor(s):
+ * Various bug fixes copyright Netymon Pty Ltd <info at netymon.com> under
+ * contract to The Topaz Foundation <info at topazproject.org>
*
* [NOTE: The text of this Exhibit A may differ slightly from the text
* of the notices in the Source Code files of the Original Code. You
@@ -32,7 +34,7 @@
import java.math.BigInteger;
// Third party packages
-import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
// Locally written packages
import org.mulgara.query.TuplesException;
@@ -59,8 +61,6 @@
*
* @modified $Date: 2005/03/07 19:42:40 $
*
- * @maintenanceAuthor $Author: newmana $
- *
* @company <A href="mailto:info at PIsoftware.com">Plugged In Software</A>
*
* @copyright © 2003 <A href="http://www.PIsoftware.com/">Plugged In
@@ -68,13 +68,100 @@
*
* @licence <a href="{@docRoot}/../../LICENCE">Mozilla Public License v1.1</a>
*/
-public class UnboundJoin extends JoinTuples {
+public class UnboundJoin extends AbstractTuples {
- static {
- logger = Category.getInstance(UnboundJoin.class.getName());
- }
+ /** Logger. */
+ private static final Logger logger =
+ Logger.getLogger(UnboundJoin.class.getName());
/**
+ * Version of {@link #operandBinding}} including only columns to the left of
+ * the first unbound column.
+ */
+ protected long[][] operandBindingPrefix;
+
+ /**
+ * For each column of the joined result, which operand contains the first
+ * occurrence of that variable.
+ */
+ protected int[] mapOperand;
+
+ /**
+ * For each column of the joined result, which column of the operand
+ * determined by {@link #mapOperand} contains the first occurrence of that
+ * variable.
+ */
+ protected int[] mapColumn;
+
+ /**
+ * Magic value within the {@link #fooOperand} array, indicating that a column
+ * is bound to one of the columns of the <var>prefix</var> parameter to
+ * {@link #next}.
+ */
+ protected static final int PREFIX = -1;
+
+ /**
+ * For each column of each operand, which operand contains the first
+ * occurrence of that variable, or {@link #PREFIX} if the prefix specified
+ * to {@link #next} contains the occurrence.
+ */
+ protected int[][] fooOperand;
+
+ /**
+ * For each column of each operand, which column of the operand determined by
+ * {@link #fooOperand} contains the first occurrence of that variable, or if
+ * the corresponding value of {@link #fooOperand} is {@link #PREFIX}, which
+ * column of the prefix specified to {@link #next} contains the occurrence.
+ */
+ protected int[][] fooColumn;
+
+ /**
+ * Whether each column of this instance might contain {@link #UNBOUND} rows.
+ */
+ protected boolean[] columnEverUnbound;
+
+ /**
+ * The propositions to conjoin.
+ */
+ protected Tuples[] operands;
+
+ /**
+ * The required values of the columns of each operand. A value of {@link
+ * Tuples#UNBOUND} indicates that the column is free to vary.
+ */
+ protected long[][] operandBinding;
+
+ /**
+ * For each operand, for each variable, which output column contains the same variable.
+ */
+ protected int[][] operandOutputMap;
+
+ /**
+ * Do any of the operands with variables matching this output variable contain UNBOUND?
+ */
+ protected boolean[][] columnOperandEverUnbound;
+
+ /**
+ * Flag indicating that the cursor is before the first row.
+ */
+ protected boolean isBeforeFirst = true;
+
+ /**
+ * Flag indicating that the cursor is after the last row.
+ */
+ protected boolean isAfterLast = false;
+
+ /**
+ * Do any of the operands contain duplicates. Used to shortcircuit hasNoDuplicates.
+ */
+ protected boolean operandsContainDuplicates;
+
+ /**
+ * The prefix of the index.
+ */
+ protected long[] prefix = null;
+
+ /**
* Conjoin a list of propositions.
*
* @param operands the propositions to conjoin; the order affects efficiency,
@@ -84,9 +171,142 @@
* @throws TuplesException EXCEPTION TO DO
*/
UnboundJoin(Tuples[] operands) throws TuplesException {
- init(operands);
+ // Validate "operands" parameter
+ if (operands == null) {
+ throw new IllegalArgumentException("Null \"operands\" parameter");
+ }
+
+ // Initialize fields
+ this.operands = clone(operands);
+ operandBinding = new long[operands.length][];
+ operandBindingPrefix = new long[operands.length][];
+ this.operandsContainDuplicates = false;
+ for (int i = 0; i < operands.length; i++) {
+ // Debug
+ if (logger.isDebugEnabled()) {
+ logger.debug("Operands " + i + " : " + operands[i]);
+ logger.debug("Operands variables " + i + " : " + Arrays.asList(operands[i].getVariables()));
+ logger.debug("Ooperands types " + i + " : " + operands[i].getClass());
+ }
+ operandBinding[i] = new long[operands[i].getVariables().length];
+ if (!operands[i].hasNoDuplicates()) {
+ this.operandsContainDuplicates = true;
+ }
+ }
+
+ fooOperand = new int[operands.length][];
+ fooColumn = new int[operands.length][];
+ operandOutputMap = new int[operands.length][];
+
+ // Calculate the variables present and their mappings from operand
+ // columns to result columns
+ List variableList = new ArrayList();
+ List mapOperandList = new ArrayList();
+ List mapColumnList = new ArrayList();
+ List fooOperandList = new ArrayList();
+ List fooColumnList = new ArrayList();
+
+ for (int i = 0; i < operands.length; i++) {
+ fooOperandList.clear();
+ fooColumnList.clear();
+
+ Variable[] operandVariables = operands[i].getVariables();
+
+ operandOutputMap[i] = new int[operandVariables.length];
+
+ for (int j = 0; j < operandVariables.length; j++) {
+ int k = variableList.indexOf(operandVariables[j]);
+
+ if (k == -1) {
+ mapOperandList.add(new Integer(i));
+ mapColumnList.add(new Integer(j));
+ fooOperandList.add(new Integer(PREFIX));
+ fooColumnList.add(new Integer(variableList.size()));
+ variableList.add(operandVariables[j]);
+ operandOutputMap[i][j] = j;
+ } else {
+ fooOperandList.add(mapOperandList.get(k));
+ fooColumnList.add(mapColumnList.get(k));
+ operandOutputMap[i][j] = k;
+ }
+ }
+
+ // Convert per-operand lists into arrays
+ assert fooOperandList.size() == fooColumnList.size();
+ fooOperand[i] = new int[fooOperandList.size()];
+ fooColumn[i] = new int[fooColumnList.size()];
+
+ for (int j = 0; j < fooOperand[i].length; j++) {
+ fooOperand[i][j] = ((Integer) fooOperandList.get(j)).intValue();
+ fooColumn[i][j] = ((Integer) fooColumnList.get(j)).intValue();
+ }
+ }
+
+ // Convert column mappings from lists to arrays
+ setVariables(variableList);
+
+ mapOperand = new int[mapOperandList.size()];
+ mapColumn = new int[mapColumnList.size()];
+
+ for (int i = 0; i < mapOperand.length; i++) {
+ mapOperand[i] = ((Integer) mapOperandList.get(i)).intValue();
+ mapColumn[i] = ((Integer) mapColumnList.get(i)).intValue();
+ }
+
+ // Determine which columns are ever unbound
+ columnEverUnbound = new boolean[variableList.size()];
+ columnOperandEverUnbound = new boolean[operands.length][variableList.size()];
+ Arrays.fill(columnEverUnbound, true);
+
+ for (int i = 0; i < operands.length; i++) {
+ Arrays.fill(columnOperandEverUnbound[i], false);
+ Variable[] variables = operands[i].getVariables();
+ for (int j = 0; j < variables.length; j++) {
+ if (!operands[i].isColumnEverUnbound(j)) {
+ columnEverUnbound[getColumnIndex(variables[j])] = false;
+ } else {
+ columnOperandEverUnbound[i][getColumnIndex(variables[j])] = true;
+ }
+ }
+ }
}
+ /**
+ * @return {@inheritDoc} This occurs if and only if every one of the
+ * {@link #operands} is unconstrained.
+ * @throws TuplesException {@inheritDoc}
+ */
+ public boolean isUnconstrained() throws TuplesException {
+ for (int i = 0; i < operands.length; i++) {
+ if (!operands[i].isUnconstrained()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public List getOperands() {
+ return Arrays.asList(operands);
+ }
+
+ public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException {
+ if (prefix == null) {
+ throw new IllegalArgumentException("Null \"prefix\" parameter");
+ }
+
+ if (suffixTruncation != 0) {
+ throw new TuplesException("Suffix truncation not implemented");
+ }
+
+ assert operands != null;
+ assert operandBinding != null;
+
+ isBeforeFirst = true;
+ isAfterLast = false;
+ this.prefix = prefix;
+ }
+
//
// Methods implementing Tuples
//
@@ -140,9 +360,7 @@
BigInteger rowCount = BigInteger.valueOf(operands[0].getRowUpperBound());
for (int i = 1; i < operands.length; i++) {
- rowCount = rowCount.multiply(BigInteger.valueOf(
- operands[i].getRowUpperBound()
- ));
+ rowCount = rowCount.multiply(BigInteger.valueOf(operands[i].getRowUpperBound()));
if (rowCount.bitLength() > 63)
return Long.MAX_VALUE;
}
@@ -150,16 +368,10 @@
return rowCount.longValue();
}
- /**
- * This method is not yet implemented, and always returns <code>true</code>.
- *
- * @return <code>true</code>
- */
public boolean isColumnEverUnbound(int column) throws TuplesException {
try {
return columnEverUnbound[column];
- }
- catch (ArrayIndexOutOfBoundsException e) {
+ } catch (ArrayIndexOutOfBoundsException e) {
throw new TuplesException("No such column " + column, e);
}
}
@@ -195,8 +407,7 @@
}
return true;
- }
- else {
+ } else {
// We know at this point that we're on a row satisfying the current
// prefix. Advance the rightmost operand and let rollover do any
// right-to-left advancement required
@@ -263,13 +474,10 @@
for (int j = 0; j < operandBinding[i].length; j++) {
if (fooOperand[i][j] == PREFIX) {
// Variable first bound to a next method parameter prefix column passed to beforeFirst.
- operandBinding[i][j] = (j < prefix.length) ? prefix[fooColumn[i][j]] :
- Tuples.UNBOUND;
- }
- else {
+ operandBinding[i][j] = (j < prefix.length) ? prefix[fooColumn[i][j]] : Tuples.UNBOUND;
+ } else {
// Variable first bound to a leftward operand column
- operandBinding[i][j] = operands[fooOperand[i][j]].getColumnValue(
- fooColumn[i][j]);
+ operandBinding[i][j] = operands[fooOperand[i][j]].getColumnValue(fooColumn[i][j]);
}
}
@@ -277,25 +485,21 @@
int prefixLength = 0;
while ((prefixLength < operandBinding[i].length) &&
(operandBinding[i][prefixLength] != Tuples.UNBOUND) &&
- (columnOperandEverUnbound[operandOutputMap[i][prefixLength]] == false)) {
+ (columnOperandEverUnbound[i][operandOutputMap[i][prefixLength]] == false)) {
prefixLength++;
}
assert prefixLength >= 0;
assert prefixLength <= operandBinding[i].length;
-// assert (prefixLength == operandBinding[i].length) ||
-// (operandBinding[i][prefixLength] == Tuples.UNBOUND);
// Generate the advancement prefix
assert operandBindingPrefix != null;
- if ((operandBindingPrefix[i] == null) ||
- (operandBindingPrefix[i].length != prefixLength)) {
+ if ((operandBindingPrefix[i] == null) || (operandBindingPrefix[i].length != prefixLength)) {
operandBindingPrefix[i] = new long[prefixLength];
}
- System.arraycopy(operandBinding[i], 0, operandBindingPrefix[i], 0,
- prefixLength);
+ System.arraycopy(operandBinding[i], 0, operandBindingPrefix[i], 0, prefixLength);
}
/**
@@ -317,8 +521,7 @@
isAfterLast = true;
prefix = null;
return false;
- }
- else {
+ } else {
// roll the leftward row
if (!advance(i - 1)) {
return false;
@@ -333,8 +536,7 @@
}
// Check that any suffix conditions are satisfied
- for (int j = operandBindingPrefix[i].length;
- j < operandBinding[i].length; j++) {
+ for (int j = operandBindingPrefix[i].length; j < operandBinding[i].length; j++) {
if ((operandBinding[i][j] != Tuples.UNBOUND) &&
(operandBinding[i][j] != operands[i].getColumnValue(j)) &&
(operands[i].getColumnValue(j) != Tuples.UNBOUND)) {
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoinUnitTest.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoinUnitTest.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnboundJoinUnitTest.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -121,6 +121,7 @@
testSuite.addTest(new UnboundJoinUnitTest("testNullPrefixBoundInSuffix"));
testSuite.addTest(new UnboundJoinUnitTest("testNullPropagation"));
testSuite.addTest(new UnboundJoinUnitTest("testLeadingPrefixNull"));
+ testSuite.addTest(new UnboundJoinUnitTest("testPartialMGR36"));
return testSuite;
@@ -577,4 +578,47 @@
TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs });
}
+
+ /**
+ * Test {@link UnboundJoin}.n the expected final join of MGR-36 case 2.
+ * <pre>
+ * s s p o x s p o x
+ * | 1 | join | 1 2 3 * | = | 1 2 3 * |
+ * | 2 4 5 * | | 1 5 3 2 |
+ * | 2 4 6 * | | 1 6 3 2 |
+ * | 1 5 3 2 |
+ * | 1 6 3 2 |
+ * </pre>
+ */
+ public void testPartialMGR36() throws Exception {
+ String[] lvars = new String[] { "s" };
+ final long[][] lhsValues = new long[][] {
+ new long[] { 1 } };
+
+ String[] rvars = new String[] { "s", "p", "o", "x" };
+ final long[][] rhsValues = new long[][] {
+ new long[] { 1, 2, 3, Tuples.UNBOUND },
+ new long[] { 1, 5, 3, 2 },
+ new long[] { 1, 6, 3, 2 },
+ new long[] { 2, 4, 5, Tuples.UNBOUND },
+ new long[] { 2, 4, 6, Tuples.UNBOUND } };
+
+
+ LiteralTuples lhs = LiteralTuples.create(lvars, lhsValues);
+ LiteralTuples rhs = LiteralTuples.create(rvars, rhsValues);
+
+ Tuples actual = TuplesOperations.sort(new UnboundJoin(new Tuples[] {lhs, rhs}));
+
+ logger.warn("testPartialMGR36 result = " + actual);
+
+ actual.beforeFirst();
+
+ TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 2, 3, Tuples.UNBOUND } );
+ TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 5, 3, 2 } );
+ TuplesTestingUtil.testTuplesRow(actual, new long[] { 1, 6, 3, 2 } );
+
+ assertTrue(!actual.next());
+
+ TuplesTestingUtil.closeTuples(new Tuples[] { actual, lhs, rhs });
+ }
}
Modified: trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnorderedProjection.java
===================================================================
--- trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnorderedProjection.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/tuples/java/org/mulgara/store/tuples/UnorderedProjection.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -256,6 +256,11 @@
throw new TuplesException("Suffix truncation not supported");
}
+ if (prefix.length > 0) {
+ throw new TuplesException("Prefix not supported in UnorderedProjection" +
+ "- use TuplesOperations.sort() to provide prefix support");
+ }
+
operand.beforeFirst(prefix, 0);
}
Modified: trunk/src/jar/util/java/org/mulgara/util/FileUtil.java
===================================================================
--- trunk/src/jar/util/java/org/mulgara/util/FileUtil.java 2007-04-25 04:33:21 UTC (rev 253)
+++ trunk/src/jar/util/java/org/mulgara/util/FileUtil.java 2007-04-26 06:06:17 UTC (rev 254)
@@ -51,6 +51,9 @@
*/
public abstract class FileUtil {
+ /** Logger. */
+ private static Logger logger = Logger.getLogger(FileUtil.class.getName());
+
/**
* Recursively delete a file or directory.
*
@@ -61,18 +64,14 @@
* @return whether the directory was successfully deleted
*/
public static boolean deleteDirectory(File directory) {
-
File[] files = directory.listFiles();
if (files != null) {
-
for (int i = 0; i < files.length; ++i) {
-
if (files[i].isFile()) {
-
- files[i].delete();
- }
- else {
-
+ if (!files[i].delete()) {
+ logger.warn("Failed to delete " + files[i]);
+ }
+ } else {
deleteDirectory(files[i]);
}
}
More information about the Mulgara-svn
mailing list