use of org.teiid.query.sql.symbol.AggregateSymbol.Type in project teiid by teiid.
the class GroupingNode method initAccumulator.
static AggregateFunction initAccumulator(AggregateSymbol aggSymbol, RelationalNode node, LinkedHashMap<Expression, Integer> expressionIndexes) {
int[] argIndexes = new int[aggSymbol.getArgs().length];
AggregateFunction result = null;
Expression[] args = aggSymbol.getArgs();
Class<?>[] inputTypes = new Class[args.length];
for (int j = 0; j < args.length; j++) {
inputTypes[j] = args[j].getType();
argIndexes[j] = getIndex(args[j], expressionIndexes);
}
Type function = aggSymbol.getAggregateFunction();
switch(function) {
case RANK:
case DENSE_RANK:
result = new RankingFunction(function);
break;
// same as count(*)
case ROW_NUMBER:
case COUNT:
result = new Count();
break;
case SUM:
result = new Sum();
break;
case AVG:
result = new Avg();
break;
case MIN:
result = new Min();
break;
case MAX:
result = new Max();
break;
case XMLAGG:
result = new XMLAgg();
break;
case ARRAY_AGG:
result = new ArrayAgg();
break;
case JSONARRAY_AGG:
result = new JSONArrayAgg();
break;
case TEXTAGG:
result = new TextAgg((TextLine) args[0]);
break;
case STRING_AGG:
result = new StringAgg(aggSymbol.getType() == DataTypeManager.DefaultDataClasses.BLOB);
break;
case FIRST_VALUE:
result = new FirstLastValue(aggSymbol.getType(), true);
break;
case LAST_VALUE:
result = new FirstLastValue(aggSymbol.getType(), false);
break;
case LEAD:
case LAG:
result = new LeadLagValue();
break;
case USER_DEFINED:
try {
result = new UserDefined(aggSymbol.getFunctionDescriptor());
} catch (FunctionExecutionException e) {
throw new TeiidRuntimeException(e);
}
break;
default:
result = new StatsFunction(function);
}
if (aggSymbol.getOrderBy() != null) {
int numOrderByItems = aggSymbol.getOrderBy().getOrderByItems().size();
List<OrderByItem> orderByItems = new ArrayList<OrderByItem>(numOrderByItems);
List<ElementSymbol> schema = createSortSchema(result, inputTypes);
argIndexes = Arrays.copyOf(argIndexes, argIndexes.length + numOrderByItems);
for (ListIterator<OrderByItem> iterator = aggSymbol.getOrderBy().getOrderByItems().listIterator(); iterator.hasNext(); ) {
OrderByItem item = iterator.next();
argIndexes[args.length + iterator.previousIndex()] = getIndex(item.getSymbol(), expressionIndexes);
ElementSymbol element = new ElementSymbol(String.valueOf(iterator.previousIndex()));
element.setType(item.getSymbol().getType());
schema.add(element);
OrderByItem newItem = item.clone();
newItem.setSymbol(element);
orderByItems.add(newItem);
}
SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), aggSymbol.isDistinct());
filter.setElements(schema);
filter.setSortItems(orderByItems);
result = filter;
} else if (aggSymbol.isDistinct()) {
SortingFilter filter = new SortingFilter(result, node.getBufferManager(), node.getConnectionID(), true);
List<ElementSymbol> elements = createSortSchema(result, inputTypes);
filter.setElements(elements);
result = filter;
}
result.setArgIndexes(argIndexes);
if (aggSymbol.getCondition() != null) {
result.setConditionIndex(getIndex(aggSymbol.getCondition(), expressionIndexes));
}
result.initialize(aggSymbol.getType(), inputTypes);
return result;
}
use of org.teiid.query.sql.symbol.AggregateSymbol.Type in project teiid by teiid.
the class QueryRewriter method rewriteCriteria.
/*
* The thing of primary importance here is that the use of the 'ANY' predicate
* quantifier is replaced with the canonical and equivalent 'SOME'
*/
private Criteria rewriteCriteria(SubqueryCompareCriteria criteria) throws TeiidComponentException, TeiidProcessingException {
rewriteWithExplicitArray(criteria.getArrayExpression(), criteria);
if (criteria.getCommand() != null && criteria.getCommand().getProcessorPlan() == null) {
if ((criteria.getOperator() == CompareCriteria.EQ && criteria.getPredicateQuantifier() != SubqueryCompareCriteria.ALL) || (criteria.getOperator() == CompareCriteria.NE && criteria.getPredicateQuantifier() == SubqueryCompareCriteria.ALL)) {
SubquerySetCriteria result = new SubquerySetCriteria(criteria.getLeftExpression(), criteria.getCommand());
result.setNegated(criteria.getOperator() == CompareCriteria.NE);
return rewriteCriteria(result);
}
if (criteria.getPredicateQuantifier() != SubqueryCompareCriteria.ALL && criteria.getOperator() != CompareCriteria.EQ && criteria.getOperator() != CompareCriteria.NE) {
CompareCriteria cc = new CompareCriteria();
cc.setLeftExpression(criteria.getLeftExpression());
boolean useView = true;
if (criteria.getCommand() instanceof Query) {
Query query = (Query) criteria.getCommand();
if (!query.hasAggregates() && query.getCriteria() != null && query.getOrderBy() == null) {
final boolean[] hasWindowFunctions = new boolean[1];
PreOrPostOrderNavigator.doVisit(query.getSelect(), new LanguageVisitor() {
public void visit(WindowFunction windowFunction) {
hasWindowFunctions[0] = true;
}
}, PreOrPostOrderNavigator.PRE_ORDER);
useView = hasWindowFunctions[0];
}
}
AggregateSymbol.Type type = Type.MAX;
if (criteria.getOperator() == CompareCriteria.GT || criteria.getOperator() == CompareCriteria.GE) {
type = Type.MIN;
}
if (useView) {
// $NON-NLS-1$
Query q = createInlineViewQuery(new GroupSymbol("X"), criteria.getCommand(), metadata, criteria.getCommand().getProjectedSymbols());
Expression ses = q.getProjectedSymbols().get(0);
Expression expr = SymbolMap.getExpression(ses);
q.getSelect().clearSymbols();
q.getSelect().addSymbol(new AggregateSymbol(type.name(), false, expr));
ScalarSubquery ss = new ScalarSubquery(q);
ss.setSubqueryHint(criteria.getSubqueryHint());
cc.setRightExpression(ss);
cc.setOperator(criteria.getOperator());
return rewriteCriteria(cc);
}
Select select = ((Query) criteria.getCommand()).getSelect();
Expression ex = select.getProjectedSymbols().get(0);
ex = SymbolMap.getExpression(ex);
select.setSymbols(Arrays.asList(new AggregateSymbol(type.name(), false, ex)));
select.setDistinct(false);
}
}
Expression leftExpr = rewriteExpressionDirect(criteria.getLeftExpression());
if (isNull(leftExpr) && criteria.getCommand() != null) {
addImplicitLimit(criteria, 1);
}
criteria.setLeftExpression(leftExpr);
if (criteria.getPredicateQuantifier() == SubqueryCompareCriteria.ANY) {
criteria.setPredicateQuantifier(SubqueryCompareCriteria.SOME);
}
rewriteSubqueryContainer(criteria, true);
if (criteria.getCommand() != null && !RelationalNodeUtil.shouldExecute(criteria.getCommand(), false, true)) {
// for example H2 treat both cases as false - however the spec and all major vendors support the following:
if (criteria.getPredicateQuantifier() == SubqueryCompareCriteria.SOME) {
return FALSE_CRITERIA;
}
return TRUE_CRITERIA;
}
return criteria;
}
use of org.teiid.query.sql.symbol.AggregateSymbol.Type in project teiid by teiid.
the class ValidationVisitor method visit.
@Override
public void visit(AggregateSymbol obj) {
if (!inQuery) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("SQLParser.Aggregate_only_top_level", obj), obj);
return;
}
if (obj.getAggregateFunction() == AggregateSymbol.Type.USER_DEFINED) {
AggregateAttributes aa = obj.getFunctionDescriptor().getMethod().getAggregateAttributes();
if (!aa.allowsDistinct() && obj.isDistinct()) {
// $NON-NLS-1$ //$NON-NLS-2$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_not_allowed", "DISTINCT", obj), obj);
}
if (!aa.allowsOrderBy() && obj.getOrderBy() != null) {
// $NON-NLS-1$ //$NON-NLS-2$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_not_allowed", "ORDER BY", obj), obj);
}
if (aa.isAnalytic() && !obj.isWindowed()) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.uda_analytic", obj), obj);
}
}
if (obj.getCondition() != null) {
Expression condition = obj.getCondition();
validateNoSubqueriesOrOuterReferences(condition);
}
Expression[] aggExps = obj.getArgs();
for (Expression expression : aggExps) {
validateNoNestedAggs(expression, obj.isWindowed());
}
validateNoNestedAggs(obj.getOrderBy(), false);
validateNoNestedAggs(obj.getCondition(), false);
// Verify data type of aggregate expression
Type aggregateFunction = obj.getAggregateFunction();
if ((aggregateFunction == Type.SUM || aggregateFunction == Type.AVG) && obj.getType() == null) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0041", new Object[] { aggregateFunction, obj }), obj);
} else if (obj.getType() != DataTypeManager.DefaultDataClasses.NULL) {
if (aggregateFunction == Type.XMLAGG && aggExps[0].getType() != DataTypeManager.DefaultDataClasses.XML) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.non_xml", new Object[] { aggregateFunction, obj }), obj);
} else if (obj.isBoolean() && aggExps[0].getType() != DataTypeManager.DefaultDataClasses.BOOLEAN) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.non_boolean", new Object[] { aggregateFunction, obj }), obj);
} else if (aggregateFunction == Type.JSONARRAY_AGG) {
validateJSONValue(obj, aggExps[0]);
} else if (obj.getType() == null) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.aggregate_type", obj), obj);
}
}
if ((obj.isDistinct() || aggregateFunction == Type.MIN || aggregateFunction == Type.MAX) && DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(aggExps[0].getType()))) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.non_comparable", new Object[] { aggregateFunction, obj }), obj);
}
if (obj.isEnhancedNumeric()) {
if (!Number.class.isAssignableFrom(aggExps[0].getType())) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0041", new Object[] { aggregateFunction, obj }), obj);
}
if (obj.isDistinct()) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("AggregateValidationVisitor.invalid_distinct", new Object[] { aggregateFunction, obj }), obj);
}
}
if (obj.isDistinct() && obj.getOrderBy() != null) {
HashSet<Expression> args = new HashSet<Expression>(Arrays.asList(obj.getArgs()));
for (OrderByItem item : obj.getOrderBy().getOrderByItems()) {
if (!args.contains(item.getSymbol())) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.distinct_orderby_agg", obj), obj);
break;
}
}
}
if (obj.getAggregateFunction() != Type.TEXTAGG) {
return;
}
TextLine tl = (TextLine) aggExps[0];
if (tl.isIncludeHeader()) {
validateDerivedColumnNames(obj, tl.getExpressions());
}
for (DerivedColumn dc : tl.getExpressions()) {
Expression expression = dc.getExpression();
if (expression.getType() == DataTypeManager.DefaultDataClasses.OBJECT || expression.getType() == null || expression.getType().isArray() || expression.getType() == DataTypeManager.DefaultDataClasses.VARBINARY || expression.getType() == DataTypeManager.DefaultDataClasses.BLOB) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.text_content_type", expression), obj);
}
}
validateTextOptions(obj, tl.getDelimiter(), tl.getQuote(), '\n');
if (tl.getEncoding() != null) {
try {
Charset.forName(tl.getEncoding());
} catch (IllegalArgumentException e) {
// $NON-NLS-1$
handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.invalid_encoding", tl.getEncoding()), obj);
}
}
}
use of org.teiid.query.sql.symbol.AggregateSymbol.Type in project teiid by teiid.
the class RulePushAggregates method buildAggregateMap.
private static Map<AggregateSymbol, Expression> buildAggregateMap(Collection<? extends AggregateSymbol> aggregateExpressions, QueryMetadataInterface metadata, Set<AggregateSymbol> nestedAggregates, boolean join) throws QueryResolverException, TeiidComponentException {
Map<AggregateSymbol, Expression> aggMap = new LinkedHashMap<AggregateSymbol, Expression>();
for (AggregateSymbol partitionAgg : aggregateExpressions) {
Expression newExpression = null;
Type aggFunction = partitionAgg.getAggregateFunction();
if (aggFunction == Type.COUNT) {
// COUNT(x) -> IFNULL(CONVERT(SUM(COUNT(x)), INTEGER), 0)
AggregateSymbol newAgg = null;
if (isCountStar(partitionAgg) && join) {
// count * case (if on the inner side of an outer join)
Function ifnull = new Function(FunctionLibrary.IFNULL, new Expression[] { partitionAgg, new Constant(1, DataTypeManager.DefaultDataClasses.INTEGER) });
newAgg = new AggregateSymbol(NonReserved.SUM, false, ifnull);
} else {
newAgg = new AggregateSymbol(NonReserved.SUM, false, partitionAgg);
}
// Build conversion function to convert SUM (which returns LONG) back to INTEGER
Function func = new Function(FunctionLibrary.CONVERT, new Expression[] { newAgg, new Constant(DataTypeManager.getDataTypeName(partitionAgg.getType())) });
if (join) {
func = new Function(FunctionLibrary.IFNULL, new Expression[] { func, new Constant(0, DataTypeManager.DefaultDataClasses.INTEGER) });
}
ResolverVisitor.resolveLanguageObject(func, metadata);
newExpression = func;
nestedAggregates.add(partitionAgg);
} else if (aggFunction == Type.AVG) {
// AVG(x) -> SUM(SUM(x)) / SUM(COUNT(x))
AggregateSymbol countAgg = new AggregateSymbol(NonReserved.COUNT, false, partitionAgg.getArg(0));
AggregateSymbol sumAgg = new AggregateSymbol(NonReserved.SUM, false, partitionAgg.getArg(0));
AggregateSymbol sumSumAgg = new AggregateSymbol(NonReserved.SUM, false, sumAgg);
AggregateSymbol sumCountAgg = new AggregateSymbol(NonReserved.SUM, false, countAgg);
Expression convertedSum = new Function(FunctionLibrary.CONVERT, new Expression[] { sumSumAgg, new Constant(DataTypeManager.getDataTypeName(partitionAgg.getType())) });
Expression convertCount = new Function(FunctionLibrary.CONVERT, new Expression[] { sumCountAgg, new Constant(DataTypeManager.getDataTypeName(partitionAgg.getType())) });
// $NON-NLS-1$
Function divideFunc = new Function("/", new Expression[] { convertedSum, convertCount });
ResolverVisitor.resolveLanguageObject(divideFunc, metadata);
newExpression = divideFunc;
nestedAggregates.add(countAgg);
nestedAggregates.add(sumAgg);
} else if (partitionAgg.isEnhancedNumeric()) {
// e.g. STDDEV_SAMP := CASE WHEN COUNT(X) > 1 THEN SQRT((SUM(X^2) - SUM(X)^2/COUNT(X))/(COUNT(X) - 1))
AggregateSymbol countAgg = new AggregateSymbol(NonReserved.COUNT, false, partitionAgg.getArg(0));
AggregateSymbol sumAgg = new AggregateSymbol(NonReserved.SUM, false, partitionAgg.getArg(0));
AggregateSymbol sumSqAgg = new AggregateSymbol(NonReserved.SUM, false, new Function(SourceSystemFunctions.POWER, new Expression[] { partitionAgg.getArg(0), new Constant(2) }));
AggregateSymbol sumSumAgg = new AggregateSymbol(NonReserved.SUM, false, sumAgg);
AggregateSymbol sumCountAgg = new AggregateSymbol(NonReserved.SUM, false, countAgg);
AggregateSymbol sumSumSqAgg = new AggregateSymbol(NonReserved.SUM, false, sumSqAgg);
Expression convertedSum = new Function(FunctionLibrary.CONVERT, new Expression[] { sumSumAgg, new Constant(DataTypeManager.DefaultDataTypes.DOUBLE) });
Function divideFunc = new Function(SourceSystemFunctions.DIVIDE_OP, new Expression[] { new Function(SourceSystemFunctions.POWER, new Expression[] { convertedSum, new Constant(2) }), sumCountAgg });
Function minusFunc = new Function(SourceSystemFunctions.SUBTRACT_OP, new Expression[] { sumSumSqAgg, divideFunc });
Expression divisor = null;
if (aggFunction == Type.STDDEV_SAMP || aggFunction == Type.VAR_SAMP) {
divisor = new Function(SourceSystemFunctions.SUBTRACT_OP, new Expression[] { sumCountAgg, new Constant(1) });
} else {
divisor = sumCountAgg;
}
Expression result = new Function(SourceSystemFunctions.DIVIDE_OP, new Expression[] { minusFunc, divisor });
if (aggFunction == Type.STDDEV_POP || aggFunction == Type.STDDEV_SAMP) {
result = new Function(SourceSystemFunctions.SQRT, new Expression[] { result });
} else {
result = new Function(FunctionLibrary.CONVERT, new Expression[] { result, new Constant(DataTypeManager.DefaultDataTypes.DOUBLE) });
}
Expression n = new Constant(0);
if (aggFunction == Type.STDDEV_SAMP || aggFunction == Type.VAR_SAMP) {
n = new Constant(1);
}
result = new SearchedCaseExpression(Arrays.asList(new CompareCriteria(sumCountAgg, CompareCriteria.GT, n)), Arrays.asList(result));
ResolverVisitor.resolveLanguageObject(result, metadata);
newExpression = result;
nestedAggregates.add(countAgg);
nestedAggregates.add(sumAgg);
nestedAggregates.add(sumSqAgg);
} else {
// AGG(X) -> AGG(AGG(X))
newExpression = new AggregateSymbol(aggFunction.name(), false, partitionAgg);
if (partitionAgg.getFunctionDescriptor() != null) {
((AggregateSymbol) newExpression).setFunctionDescriptor(partitionAgg.getFunctionDescriptor().clone());
}
nestedAggregates.add(partitionAgg);
}
aggMap.put(partitionAgg, newExpression);
}
return aggMap;
}
use of org.teiid.query.sql.symbol.AggregateSymbol.Type in project teiid by teiid.
the class FunctionLibrary method getBuiltInAggregateFunctions.
/**
* Return a list of the most general forms of built-in aggregate functions.
* <br/>count(*) - is not included
* <br/>textagg - is not included due to its non standard syntax
*
* @param includeAnalytic - true to include analytic functions that must be windowed
* @return
*/
public List<FunctionMethod> getBuiltInAggregateFunctions(boolean includeAnalytic) {
ArrayList<FunctionMethod> result = new ArrayList<FunctionMethod>();
if (this.systemFunctions != null) {
FunctionDescriptor stExtent = this.systemFunctions.getFunction(SourceSystemFunctions.ST_EXTENT, new Class[] { DataTypeManager.DefaultDataClasses.GEOMETRY });
result.add(stExtent.getMethod());
}
for (Type type : AggregateSymbol.Type.values()) {
AggregateAttributes aa = new AggregateAttributes();
String returnType = null;
String[] argTypes = null;
aa.setAllowsDistinct(true);
switch(type) {
case TEXTAGG:
case USER_DEFINED:
continue;
case DENSE_RANK:
case RANK:
case ROW_NUMBER:
if (!includeAnalytic) {
continue;
}
aa.setAllowsDistinct(false);
aa.setAnalytic(true);
returnType = DataTypeManager.DefaultDataTypes.INTEGER;
argTypes = new String[] {};
break;
case ANY:
case SOME:
case EVERY:
returnType = DataTypeManager.DefaultDataTypes.BOOLEAN;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.BOOLEAN };
break;
case COUNT:
returnType = DataTypeManager.DefaultDataTypes.INTEGER;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT };
break;
case MAX:
case MIN:
case AVG:
case SUM:
returnType = DataTypeManager.DefaultDataTypes.OBJECT;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT };
break;
case STDDEV_POP:
case STDDEV_SAMP:
case VAR_POP:
case VAR_SAMP:
returnType = DataTypeManager.DefaultDataTypes.DOUBLE;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.DOUBLE };
break;
case STRING_AGG:
returnType = DataTypeManager.DefaultDataTypes.OBJECT;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT };
aa.setAllowsOrderBy(true);
break;
case ARRAY_AGG:
returnType = DataTypeManager.DefaultDataTypes.OBJECT;
argTypes = new String[] { DataTypeManager.getDataTypeName(DataTypeManager.getArrayType(DataTypeManager.DefaultDataClasses.OBJECT)) };
aa.setAllowsOrderBy(true);
aa.setAllowsDistinct(false);
break;
case JSONARRAY_AGG:
returnType = DataTypeManager.DefaultDataTypes.CLOB;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT };
aa.setAllowsOrderBy(true);
aa.setAllowsDistinct(false);
break;
case XMLAGG:
returnType = DataTypeManager.DefaultDataTypes.XML;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.XML };
aa.setAllowsOrderBy(true);
aa.setAllowsDistinct(false);
break;
case FIRST_VALUE:
case LAST_VALUE:
if (!includeAnalytic) {
continue;
}
aa.setAllowsDistinct(false);
aa.setAnalytic(true);
returnType = DataTypeManager.DefaultDataTypes.OBJECT;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT };
break;
case LEAD:
case LAG:
if (!includeAnalytic) {
continue;
}
aa.setAllowsDistinct(false);
aa.setAnalytic(true);
returnType = DataTypeManager.DefaultDataTypes.OBJECT;
argTypes = new String[] { DataTypeManager.DefaultDataTypes.OBJECT, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.OBJECT };
break;
}
FunctionMethod fm = FunctionMethod.createFunctionMethod(type.name(), type.name(), FunctionCategoryConstants.AGGREGATE, returnType, argTypes);
fm.setAggregateAttributes(aa);
result.add(fm);
}
return result;
}
Aggregations