/* * Copyright 2010 Duraspace, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mulgara.store.tuples; // Java 2 standard packages import java.util.*; // Locally written packages import org.apache.log4j.Logger; import org.mulgara.query.TuplesException; import org.mulgara.query.Variable; import org.mulgara.util.functional.C; /** * Projection to include new columns that will be unbound. This is a thin wrapper * and will maintain almost all the properties of the wrapped Tuples. * * @created 2010-01-06 * @author Paula Gearon * @copyright © 2010 <a href="http://www.fedora-commons.org/">Fedora Commons</a> */ class ExpandedProjection extends AbstractTuples { /** Logger. */ private final static Logger logger = Logger.getLogger(ExpandedProjection.class); /** The proposition to project. */ private final Tuples operand; /** Projected variable array. */ private final Variable[] variables; /** Width of the original tuples. */ private final int opWidth; /** * Eliminate columns from a {@link Tuples}. This does not eliminate * duplicates; {@link DistinctTuples} should be used to produce a formal * relational projection. * * @param operand the tuples to project * @param newVars the columns to add * @throws IllegalArgumentException if <var>operand</var> is <code>null</code> */ ExpandedProjection(Tuples operand, List<Variable> newVars) { assert operand != null; assert newVars != null; assert !newVars.isEmpty(); // get the existing a new variables Variable[] opVars = operand.getVariables(); assert C.intersect(newVars, opVars).isEmpty(); if (logger.isDebugEnabled() && newVars.isEmpty()) { logger.debug("No extra variables in tuples expansion"); } // Initialize fields opWidth = opVars.length; this.operand = (Tuples)operand.clone(); this.variables = new Variable[opWidth + newVars.size()]; // copy the original columns to the start of the variables array System.arraycopy(opVars, 0, this.variables, 0, opWidth); // copy the new "unbound" columns to the end of the variables array int i = opWidth; for (Variable v: newVars) this.variables[i++] = v; assert i == this.variables.length; } /** * Cloning constructor. * @param parent The original Tuples to be cloned from */ private ExpandedProjection(ExpandedProjection parent) { operand = (Tuples)parent.operand.clone(); variables = parent.variables; opWidth = parent.opWidth; } /** * Gets the ColumnValue attribute of the OrderedProjection object * @param column Specifies the column number to get the value for. * @return The value for the variable binding, unbound if in an expanded column. * @throws TuplesException Error accessing the underlying Tuples */ public long getColumnValue(int column) throws TuplesException { assert (column >= 0) && (column < variables.length) : "Invalid column " + column; return column < opWidth ? operand.getColumnValue(column) : UNBOUND; } /** * Gets the Comparator attribute of the OrderedProjection object * @return The Comparator value */ public RowComparator getComparator() { return operand.getComparator(); } /** * Gets the RowCount attribute of the OrderedProjection object * @return The RowCount value * @throws TuplesException Error on underlying data */ public long getRowCount() throws TuplesException { return operand.getRowCount(); } public long getRowUpperBound() throws TuplesException { return operand.getRowUpperBound(); } public long getRowExpectedCount() throws TuplesException { return operand.getRowExpectedCount(); } public int getRowCardinality() throws TuplesException { return operand.getRowCardinality(); } public boolean isEmpty() throws TuplesException { return operand.isEmpty(); } /** * Gets the Variables attribute of the OrderedProjection object * @return The Variables value */ public Variable[] getVariables() { return variables; } /** * A column may be unbound if it's unbound in the projection operand. */ public boolean isColumnEverUnbound(int column) throws TuplesException { assert (column >= 0) && (column < variables.length) : "Invalid column " + column; // yes there's a boolean expression for the following, but this is easier to read return column < opWidth ? operand.isColumnEverUnbound(column) : true; } /** * Gets the Materialized attribute of the OrderedProjection object * @return The Materialized value */ public boolean isMaterialized() { return operand.isMaterialized(); } /** * @return whether every operand is unconstrained * @throws TuplesException Error in the underlying data */ public boolean isUnconstrained() throws TuplesException { return operand.isUnconstrained(); } public List<Tuples> getOperands() { return Collections.singletonList(operand); } // // Methods implementing Tuples // /** * Go the the first binding that matches a given prefix. * @param prefix A pattern specifying the first thing to test against. * @param suffixTruncation Not accepted. Must be 0. * @throws TuplesException Error in the underlying Tuples, or a non-zero suffixTruncation. */ public void beforeFirst(long[] prefix, int suffixTruncation) throws TuplesException { if (suffixTruncation != 0) throw new TuplesException("Suffix truncation not implemented"); // truncate the prefix if it is wider than the first operand. It can't match to UNBOUND anyway. if (prefix.length > opWidth) { long[] tmp = prefix; prefix = new long[opWidth]; System.arraycopy(tmp, 0, prefix, 0, opWidth); } operand.beforeFirst(prefix, 0); } /** * Closes this resource and all attached resources. * @throws TuplesException Error in the underlying tuples. */ public void close() throws TuplesException { operand.close(); } /** * Tests if this tuples has duplicate rows * @return <code>true</code> iff the underyling tuples has no duplicates. * @throws TuplesException Error in the underlying Tuples */ public boolean hasNoDuplicates() throws TuplesException { return operand.hasNoDuplicates(); } /** * Move to the next binding on this Tuples. * @return <code>true</code> if there is more data to move to. * @throws TuplesException Error in the udnerlying Tuples */ public boolean next() throws TuplesException { return operand.next(); } // // Methods overriding Object // /** * Clones this object * @return A new and identical tuples */ public Object clone() { return new ExpandedProjection(this); } }