use of org.apache.derby.iapi.types.DataTypeDescriptor in project derby by apache.
the class InListOperatorNode method getDominantType.
/**
* Get the dominant type of all the operands in this IN list.
* @return the type descriptor for the dominant type
* @see DataTypeDescriptor#getDominantType(DataTypeDescriptor, ClassFactory)
*/
private DataTypeDescriptor getDominantType() {
DataTypeDescriptor targetType = leftOperand.getTypeServices();
TypeId judgeTypeId = targetType.getTypeId();
if (!rightOperandList.allSamePrecendence(judgeTypeId.typePrecedence())) {
// Iterate through the entire list of values to find out
// what the dominant type is.
ClassFactory cf = getClassFactory();
for (ValueNode vn : rightOperandList) {
targetType = targetType.getDominantType(vn.getTypeServices(), cf);
}
}
return targetType;
}
use of org.apache.derby.iapi.types.DataTypeDescriptor 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.DataTypeDescriptor in project derby by apache.
the class JavaToSQLValueNode method bindExpression.
/**
* Bind this expression. This means binding the sub-expressions,
* as well as figuring out what the return type is for this expression.
*
* @param fromList The FROM list for the query this
* expression is in, for binding columns.
* @param subqueryList The subquery list being built as we find
* SubqueryNodes
* @param aggregates The aggregate list being built as we find
* AggregateNodes
*
* @return The new top of the expression tree.
*
* @exception StandardException Thrown on error
*/
@Override
ValueNode bindExpression(FromList fromList, SubqueryList subqueryList, List<AggregateNode> aggregates) throws StandardException {
// method invocations are not allowed in ADD TABLE clauses.
// And neither are field references.
javaNode.checkReliability(this);
/* Bind the expression under us */
javaNode = javaNode.bindExpression(fromList, subqueryList, aggregates);
if (javaNode instanceof StaticMethodCallNode) {
AggregateNode agg = ((StaticMethodCallNode) javaNode).getResolvedAggregate();
if (agg != null) {
return agg.bindExpression(fromList, subqueryList, aggregates);
}
}
DataTypeDescriptor dts = javaNode.getDataType();
if (dts == null) {
throw StandardException.newException(SQLState.LANG_NO_CORRESPONDING_S_Q_L_TYPE, javaNode.getJavaTypeName());
}
TypeDescriptor catalogType = dts.getCatalogType();
if (catalogType.isRowMultiSet() || (catalogType.getTypeName().equals("java.sql.ResultSet"))) {
throw StandardException.newException(SQLState.LANG_TABLE_FUNCTION_NOT_ALLOWED);
}
setType(dts);
// RoutineAliasInfo to javaNode.
if (dts.getTypeId().isStringTypeId()) {
this.setCollationInfo(javaNode.getCollationType(), StringDataValue.COLLATION_DERIVATION_IMPLICIT);
}
return this;
}
use of org.apache.derby.iapi.types.DataTypeDescriptor in project derby by apache.
the class NumericTypeCompiler method resolveArithmeticOperation.
/**
* @see TypeCompiler#resolveArithmeticOperation
*
* @exception StandardException Thrown on error
*/
@Override
public DataTypeDescriptor resolveArithmeticOperation(DataTypeDescriptor leftType, DataTypeDescriptor rightType, String operator) throws StandardException {
NumericTypeCompiler higherTC;
DataTypeDescriptor higherType;
boolean nullable;
int precision, scale, maximumWidth;
/*
** Check the right type to be sure it's a number. By convention,
** we call this method off the TypeId of the left operand, so if
** we get here, we know the left operand is a number.
*/
if (SanityManager.DEBUG)
SanityManager.ASSERT(leftType.getTypeId().isNumericTypeId(), "The left type is supposed to be a number because we're resolving an arithmetic operator");
TypeId leftTypeId = leftType.getTypeId();
TypeId rightTypeId = rightType.getTypeId();
boolean supported = true;
if (!(rightTypeId.isNumericTypeId())) {
supported = false;
}
if (TypeCompiler.MOD_OP.equals(operator)) {
switch(leftTypeId.getJDBCTypeId()) {
case java.sql.Types.TINYINT:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
case java.sql.Types.BIGINT:
break;
default:
supported = false;
break;
}
switch(rightTypeId.getJDBCTypeId()) {
case java.sql.Types.TINYINT:
case java.sql.Types.SMALLINT:
case java.sql.Types.INTEGER:
case java.sql.Types.BIGINT:
break;
default:
supported = false;
break;
}
}
if (!supported) {
throw StandardException.newException(SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED, operator, leftType.getTypeId().getSQLTypeName(), rightType.getTypeId().getSQLTypeName());
}
/*
** Take left as the higher precedence if equal
*/
if (rightTypeId.typePrecedence() > leftTypeId.typePrecedence()) {
higherType = rightType;
higherTC = (NumericTypeCompiler) getTypeCompiler(rightTypeId);
} else {
higherType = leftType;
higherTC = (NumericTypeCompiler) getTypeCompiler(leftTypeId);
}
/* The calculation of precision and scale should be based upon
* the type with higher precedence, which is going to be the result
* type, this is also to be consistent with maximumWidth. Beetle 3906.
*/
precision = higherTC.getPrecision(operator, leftType, rightType);
if (higherType.getTypeId().isDecimalTypeId()) {
scale = higherTC.getScale(operator, leftType, rightType);
maximumWidth = (scale > 0) ? precision + 3 : precision + 1;
/*
** Be careful not to overflow
*/
if (maximumWidth < precision) {
maximumWidth = Integer.MAX_VALUE;
}
} else {
scale = 0;
maximumWidth = higherType.getMaximumWidth();
}
/* The result is nullable if either side is nullable */
nullable = leftType.isNullable() || rightType.isNullable();
/*
** The higher type does not have the right nullability. Create a
** new DataTypeDescriptor that has the correct type and nullability.
**
** It's OK to call the implementation of the DataTypeDescriptorFactory
** here, because we're in the same package.
*/
return new DataTypeDescriptor(higherType.getTypeId(), precision, scale, nullable, maximumWidth);
}
use of org.apache.derby.iapi.types.DataTypeDescriptor 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;
}
Aggregations