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;
}
}
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;
}
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);
}
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;
}
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;
}
Aggregations