Search in sources :

Example 76 with DataValueDescriptor

use of org.apache.derby.iapi.types.DataValueDescriptor in project derby by apache.

the class InListOperatorNode method preprocess.

/**
 * Preprocess an expression tree.  We do a number of transformations
 * here (including subqueries, IN lists, LIKE and BETWEEN) plus
 * subquery flattening.
 * NOTE: This is done before the outer ResultSetNode is preprocessed.
 *
 * @param	numTables			Number of tables in the DML Statement
 * @param	outerFromList		FromList from outer query block
 * @param	outerSubqueryList	SubqueryList from outer query block
 * @param	outerPredicateList	PredicateList from outer query block
 *
 * @return		The modified expression
 *
 * @exception StandardException		Thrown on error
 */
@Override
ValueNode preprocess(int numTables, FromList outerFromList, SubqueryList outerSubqueryList, PredicateList outerPredicateList) throws StandardException {
    super.preprocess(numTables, outerFromList, outerSubqueryList, outerPredicateList);
    /* Check for the degenerate case of a single element in the IN list.
		 * If found, then convert to "=".
		 */
    if (rightOperandList.size() == 1) {
        BinaryComparisonOperatorNode equal = new BinaryRelationalOperatorNode(BinaryRelationalOperatorNode.K_EQUALS, leftOperand, rightOperandList.elementAt(0), false, getContextManager());
        /* Set type info for the operator node */
        equal.bindComparisonOperator();
        return equal;
    }
    // DERBY-6017: All comparisons have to be performed using the dominant
    // type of *all* the values in the left operand and the right operand.
    // If either the left operand is of the dominant type, or all of the
    // values in the right operand are of the dominant type, we know that
    // each comparison will be performed using the dominant type.
    // Otherwise, cast the left operand to the dominant type to ensure
    // that each comparison operation will use the dominant type.
    DataTypeDescriptor targetType = getDominantType();
    int targetTypePrecedence = targetType.getTypeId().typePrecedence();
    if ((leftOperand.getTypeServices().getTypeId().typePrecedence() != targetTypePrecedence) && !rightOperandList.allSamePrecendence(targetTypePrecedence)) {
        CastNode cn = new CastNode(leftOperand, targetType, getContextManager());
        cn.bindCastNodeOnly();
        leftOperand = cn;
    }
    if ((leftOperand instanceof ColumnReference) && rightOperandList.containsOnlyConstantAndParamNodes()) {
        /* At this point we have an IN-list made up of constant and/or
			 * parameter values.  Ex.:
			 *
			 *  select id, name from emp where id in (34, 28, ?)
			 *
			 * Since the optimizer does not recognize InListOperatorNodes
			 * as potential start/stop keys for indexes, it (the optimizer)
			 * may estimate that the cost of using any of the indexes would
			 * be too high.  So we could--and probably would--end up doing
			 * a table scan on the underlying base table. But if the number
			 * of rows in the base table is significantly greater than the
			 * number of values in the IN-list, scanning the base table can
			 * be overkill and can lead to poor performance.  And further,
			 * choosing to use an index but then scanning the entire index
			 * can be slow, too. DERBY-47.
			 *
			 * What we do, then, is create an "IN-list probe predicate",
			 * which is an internally generated equality predicate with a
			 * parameter value on the right.  So for the query shown above
			 * the probe predicate would be "id = ?".  We then replace
			 * this InListOperatorNode with the probe predicate during
			 * optimization.  The optimizer in turn recognizes the probe
			 * predicate, which is disguised to look like a typical binary
			 * equality, as a potential start/stop key for any indexes.
			 * This start/stop key potential then factors into the estimated
			 * cost of probing the indexes, which leads to a more reasonable
			 * estimate and thus makes it more likely that the optimizer
			 * will choose to use an index vs a table scan.  That done, we
			 * then use the probe predicate to perform multiple execution-
			 * time "probes" on the index--instead of doing a range index
			 * scan--which eliminates unnecessary scanning. For more see
			 * execute/MultiProbeTableScanResultSet.java.
			 *
			 * With this approach we know that regardless of how large the
			 * base table is, we'll only have to probe the index a max of
			 * N times, where "N" is the size of the IN-list. If N is
			 * significantly less than the number of rows in the table, or
			 * is significantly less than the number of rows between the
			 * min value and the max value in the IN-list, this selective
			 * probing can save us a lot of time.
			 *
			 * Note: We will do fewer than N probes if there are duplicates
			 * in the list.
			 *
			 * Note also that, depending on the relative size of the IN-list
			 * verses the number of rows in the table, it may actually be
			 * better to just do a table scan--especially if there are fewer
			 * rows in the table than there are in the IN-list.  So even though
			 * we create a "probe predicate" and pass it to the optimizer, it
			 * (the optimizer) may still choose to do a table scan.  If that
			 * happens then we'll "revert" the probe predicate back to its
			 * original form (i.e. to this InListOperatorNode) during code
			 * generation, and then we'll use it as a regular IN-list
			 * restriction when it comes time to execute.
			 */
        boolean allConstants = rightOperandList.containsAllConstantNodes();
        /* If we have all constants then sort them now.  This allows us to
			 * skip the sort at execution time (we have to sort them so that
			 * we can eliminate duplicate IN-list values).  If we have one
			 * or more parameter nodes then we do *not* sort the values here
			 * because we do not (and cannot) know what values the parameter(s)
			 * will have.  In that case we'll sort the values at execution
			 * time. 
			 */
        if (allConstants) {
            /* When sorting or choosing min/max in the list, if types
				 * are not an exact match then we have to use the *dominant*
				 * type across all values, where "all values" includes the
				 * left operand.  Otherwise we can end up with incorrect
				 * results.
				 *
				 * Note that it is *not* enough to just use the left operand's
				 * type as the judge because we have no guarantee that the
				 * left operand has the dominant type.  If, for example, the
				 * left operand has type INTEGER and all (or any) values in
				 * the IN list have type DECIMAL, use of the left op's type
				 * would lead to comparisons with truncated values and could
				 * therefore lead to an incorrect sort order. DERBY-2256.
				 */
            /* Now sort the list in ascending order using the dominant
				 * type found above.
				 */
            DataValueDescriptor judgeODV = targetType.getNull();
            rightOperandList.sortInAscendingOrder(judgeODV);
            isOrdered = true;
            ValueNode minValue = rightOperandList.elementAt(0);
            ValueNode maxValue = rightOperandList.elementAt(rightOperandList.size() - 1);
            /* Handle the degenerate case where the min and the max
				 * are the same value.  Note (again) that we need to do
				 * this comparison using the dominant type found above.
				 */
            DataValueDescriptor minODV = ((ConstantNode) minValue).getValue();
            DataValueDescriptor maxODV = ((ConstantNode) maxValue).getValue();
            if (judgeODV.equals(minODV, maxODV).equals(true)) {
                BinaryComparisonOperatorNode equal = new BinaryRelationalOperatorNode(BinaryRelationalOperatorNode.K_EQUALS, leftOperand, minValue, false, getContextManager());
                /* Set type info for the operator node */
                equal.bindComparisonOperator();
                return equal;
            }
        }
        /* Create a parameter node to serve as the right operand of
			 * the probe predicate.  We intentionally use a parameter node
			 * instead of a constant node because the IN-list has more than
			 * one value (some of which may be unknown at compile time, i.e.
			 * if they are parameters), so we don't want an estimate based
			 * on any single literal.  Instead we want a generic estimate
			 * of the cost to retrieve the rows matching some _unspecified_
			 * value (namely, one of the values in the IN-list, but we
			 * don't know which one).  That's exactly what a parameter
			 * node gives us.
			 *
			 * Note: If the IN-list only had a single value then we would
			 * have taken the "if (rightOperandList.size() == 1)" branch
			 * above and thus would not be here.
			 *
			 * We create the parameter node based on the first value in
			 * the list.  This is arbitrary and should not matter in the
			 * big picture.
			 */
        ValueNode srcVal = rightOperandList.elementAt(0);
        ParameterNode pNode = new ParameterNode(0, // default value
        null, getContextManager());
        DataTypeDescriptor pType = srcVal.getTypeServices();
        pNode.setType(pType);
        /* If we choose to use the new predicate for execution-time
			 * probing then the right operand will function as a start-key
			 * "place-holder" into which we'll store the different IN-list
			 * values as we iterate through them.  This means we have to
			 * generate a valid value for the parameter node--i.e. for the
			 * right side of the probe predicate--in order to have a valid
			 * execution-time placeholder.  To do that we pass the source
			 * value from which we found the type down to the new, "fake"
			 * parameter node.  Then, when it comes time to generate the
			 * parameter node, we'll just generate the source value as our
			 * place-holder.  See ParameterNode.generateExpression().
			 *
			 * Note: the actual value of the "place-holder" does not matter
			 * because it will be clobbered by the various IN-list values
			 * (which includes "srcVal" itself) as we iterate through them
			 * during execution.
			 */
        pNode.setValueToGenerate(srcVal);
        /* Finally, create the "column = ?" equality that serves as the
			 * basis for the probe predicate.  We store a reference to "this"
			 * node inside the probe predicate so that, if we later decide
			 * *not* to use the probe predicate for execution time index
			 * probing, we can revert it back to its original form (i.e.
			 * to "this").
			 */
        BinaryComparisonOperatorNode equal = new BinaryRelationalOperatorNode(BinaryRelationalOperatorNode.K_EQUALS, leftOperand, pNode, this, false, getContextManager());
        /* Set type info for the operator node */
        equal.bindComparisonOperator();
        return equal;
    } else {
        return this;
    }
}
Also used : DataTypeDescriptor(org.apache.derby.iapi.types.DataTypeDescriptor) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor)

Example 77 with DataValueDescriptor

use of org.apache.derby.iapi.types.DataValueDescriptor in project derby by apache.

the class ResultColumnList method buildEmptyRow.

/**
 *	Build an empty row with the size and shape of the ResultColumnList.
 *
 *	@return	an empty row of the correct size and shape.
 * @exception StandardException		Thrown on error
 */
public ExecRow buildEmptyRow() throws StandardException {
    int columnCount = size();
    ExecRow row = getExecutionFactory().getValueRow(columnCount);
    int position = 1;
    for (ResultColumn rc : this) {
        DataTypeDescriptor dataType = rc.getTypeServices();
        DataValueDescriptor dataValue = dataType.getNull();
        row.setColumn(position++, dataValue);
    }
    return row;
}
Also used : DataTypeDescriptor(org.apache.derby.iapi.types.DataTypeDescriptor) ExecRow(org.apache.derby.iapi.sql.execute.ExecRow) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor)

Example 78 with DataValueDescriptor

use of org.apache.derby.iapi.types.DataValueDescriptor in project derby by apache.

the class RowUtil method qualifyRow.

/**
 * Process the qualifier list on the row, return true if it qualifies.
 * <p>
 * A two dimensional array is to be used to pass around a AND's and OR's in
 * conjunctive normal form.  The top slot of the 2 dimensional array is
 * optimized for the more frequent where no OR's are present.  The first
 * array slot is always a list of AND's to be treated as described above
 * for single dimensional AND qualifier arrays.  The subsequent slots are
 * to be treated as AND'd arrays or OR's.  Thus the 2 dimensional array
 * qual[][] argument is to be treated as the following, note if
 * qual.length = 1 then only the first array is valid and it is and an
 * array of and clauses:
 *
 * (qual[0][0] and qual[0][0] ... and qual[0][qual[0].length - 1])
 * and
 * (qual[1][0] or  qual[1][1] ... or  qual[1][qual[1].length - 1])
 * and
 * (qual[2][0] or  qual[2][1] ... or  qual[2][qual[2].length - 1])
 * ...
 * and
 * (qual[qual.length - 1][0] or  qual[1][1] ... or  qual[1][2])
 *
 * @return true if the row qualifies.
 *
 * @param row               The row being qualified.
 * @param qual_list         2 dimensional array representing conjunctive
 *                          normal form of simple qualifiers.
 *
 * @exception  StandardException  Standard exception policy.
 */
public static final boolean qualifyRow(DataValueDescriptor[] row, Qualifier[][] qual_list) throws StandardException {
    boolean row_qualifies = true;
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(row != null);
    }
    if (SanityManager.DEBUG) {
        // routine should not be called if there is no qualifier
        SanityManager.ASSERT(qual_list != null);
        SanityManager.ASSERT(qual_list.length > 0);
    }
    for (int i = 0; i < qual_list[0].length; i++) {
        // process each AND clause
        row_qualifies = false;
        // process each OR clause.
        Qualifier q = qual_list[0][i];
        // Get the column from the possibly partial row, of the
        // q.getColumnId()'th column in the full row.
        DataValueDescriptor columnValue = row[q.getColumnId()];
        row_qualifies = columnValue.compare(q.getOperator(), q.getOrderable(), q.getOrderedNulls(), q.getUnknownRV());
        if (q.negateCompareResult())
            row_qualifies = !row_qualifies;
        // Once an AND fails the whole Qualification fails - do a return!
        if (!row_qualifies)
            return (false);
    }
    for (int and_idx = 1; and_idx < qual_list.length; and_idx++) {
        // loop through each of the "and" clause.
        row_qualifies = false;
        if (SanityManager.DEBUG) {
            // Each OR clause must be non-empty.
            SanityManager.ASSERT(qual_list[and_idx].length > 0);
        }
        for (int or_idx = 0; or_idx < qual_list[and_idx].length; or_idx++) {
            // Apply one qualifier to the row.
            Qualifier q = qual_list[and_idx][or_idx];
            int col_id = q.getColumnId();
            if (SanityManager.DEBUG) {
                SanityManager.ASSERT((col_id < row.length), "Qualifier is referencing a column not in the row.");
            }
            // Get the column from the possibly partial row, of the
            // q.getColumnId()'th column in the full row.
            DataValueDescriptor columnValue = row[q.getColumnId()];
            if (SanityManager.DEBUG) {
                if (columnValue == null)
                    SanityManager.THROWASSERT("1:row = " + RowUtil.toString(row) + "row.length = " + row.length + ";q.getColumnId() = " + q.getColumnId());
            }
            // do the compare between the column value and value in the
            // qualifier.
            row_qualifies = columnValue.compare(q.getOperator(), q.getOrderable(), q.getOrderedNulls(), q.getUnknownRV());
            if (q.negateCompareResult())
                row_qualifies = !row_qualifies;
            // to go and process next AND clause.
            if (row_qualifies)
                break;
        }
        // qualifications so as soon as one is false processing is done.
        if (!row_qualifies)
            break;
    }
    return (row_qualifies);
}
Also used : DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor)

Example 79 with DataValueDescriptor

use of org.apache.derby.iapi.types.DataValueDescriptor in project derby by apache.

the class BackingStoreHashtable method getEstimatedMemUsage.

/**
 * Take a value which will go into the hash table and return an estimate
 * of how much memory that value will consume. The hash value could
 * be either an array of columns or a LocatedRow.
 *
 * @param hashValue The object for which we want to know the memory usage.
 * @return A guess as to how much memory the current hash value will
 *  use.
 */
private long getEstimatedMemUsage(Object hashValue) {
    long rowMem = 0;
    DataValueDescriptor[] row = null;
    if (hashValue instanceof DataValueDescriptor[]) {
        row = (DataValueDescriptor[]) hashValue;
    } else {
        LocatedRow locatedRow = (LocatedRow) hashValue;
        row = locatedRow.columnValues();
        // account for the RowLocation size and class overhead
        RowLocation rowLocation = locatedRow.rowLocation();
        if (rowLocation != null) {
            rowMem += locatedRow.rowLocation().estimateMemoryUsage();
            rowMem += ClassSize.refSize;
        }
        // account for class overhead of the LocatedRow itself
        rowMem += ClassSize.refSize;
    }
    for (int i = 0; i < row.length; i++) {
        // account for the column's size and class overhead
        rowMem += row[i].estimateMemoryUsage();
        rowMem += ClassSize.refSize;
    }
    // account for the class overhead of the array itself
    rowMem += ClassSize.refSize;
    return rowMem;
}
Also used : LocatedRow(org.apache.derby.iapi.types.LocatedRow) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor) RowLocation(org.apache.derby.iapi.types.RowLocation)

Example 80 with DataValueDescriptor

use of org.apache.derby.iapi.types.DataValueDescriptor in project derby by apache.

the class BackingStoreHashtable method makeDiskRow.

// end of spillToDisk
/**
 * <p>
 * Make a full set of columns from an object which is either already
 * an array of column or otherwise a LocatedRow. The full set of columns
 * is what's stored on disk when we spill to disk. This is the inverse of
 * makeInMemoryRow().
 * </p>
 */
private DataValueDescriptor[] makeDiskRow(Object raw) {
    DataValueDescriptor[] allColumns = null;
    if (includeRowLocations()) {
        LocatedRow locatedRow = (LocatedRow) raw;
        allColumns = makeDiskRow(locatedRow.columnValues(), locatedRow.rowLocation());
    } else {
        allColumns = (DataValueDescriptor[]) raw;
    }
    return allColumns;
}
Also used : LocatedRow(org.apache.derby.iapi.types.LocatedRow) DataValueDescriptor(org.apache.derby.iapi.types.DataValueDescriptor)

Aggregations

DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)328 ExecIndexRow (org.apache.derby.iapi.sql.execute.ExecIndexRow)72 ExecRow (org.apache.derby.iapi.sql.execute.ExecRow)62 RowLocation (org.apache.derby.iapi.types.RowLocation)54 SQLLongint (org.apache.derby.iapi.types.SQLLongint)51 StandardException (org.apache.derby.shared.common.error.StandardException)43 SQLChar (org.apache.derby.iapi.types.SQLChar)42 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)36 SQLVarchar (org.apache.derby.iapi.types.SQLVarchar)36 ScanController (org.apache.derby.iapi.store.access.ScanController)35 ConglomerateController (org.apache.derby.iapi.store.access.ConglomerateController)32 UUID (org.apache.derby.catalog.UUID)31 TupleDescriptor (org.apache.derby.iapi.sql.dictionary.TupleDescriptor)24 RawTransaction (org.apache.derby.iapi.store.raw.xact.RawTransaction)16 DataDescriptorGenerator (org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator)15 RawContainerHandle (org.apache.derby.iapi.store.raw.data.RawContainerHandle)15 DataTypeDescriptor (org.apache.derby.iapi.types.DataTypeDescriptor)15 Properties (java.util.Properties)14 UserType (org.apache.derby.iapi.types.UserType)13 Page (org.apache.derby.iapi.store.raw.Page)11