use of io.prestosql.execution.warnings.WarningCollector in project hetu-core by openlookeng.
the class TestPlannerWarnings method assertPlannerWarnings.
public static void assertPlannerWarnings(LocalQueryRunner queryRunner, @Language("SQL") String sql, Map<String, String> sessionProperties, List<WarningCode> expectedWarnings, Optional<List<Rule<?>>> rules) {
Session.SessionBuilder sessionBuilder = testSessionBuilder().setCatalog(queryRunner.getDefaultSession().getCatalog().get()).setSchema(queryRunner.getDefaultSession().getSchema().get());
sessionProperties.forEach(sessionBuilder::setSystemProperty);
WarningCollector warningCollector = new DefaultWarningCollector(new WarningCollectorConfig());
try {
queryRunner.inTransaction(sessionBuilder.build(), transactionSession -> {
if (rules.isPresent()) {
createPlan(queryRunner, transactionSession, sql, warningCollector, rules.get());
} else {
queryRunner.createPlan(transactionSession, sql, LogicalPlanner.Stage.CREATED, false, warningCollector);
}
return null;
});
} catch (SemanticException e) {
// ignore
}
Set<WarningCode> warnings = warningCollector.getWarnings().stream().map(PrestoWarning::getWarningCode).collect(toImmutableSet());
for (WarningCode expectedWarning : expectedWarnings) {
if (!warnings.contains(expectedWarning)) {
fail("Expected warning: " + expectedWarning);
}
}
}
use of io.prestosql.execution.warnings.WarningCollector in project hetu-core by openlookeng.
the class LocalDispatchQueryFactory method createDispatchQuery.
@Override
public DispatchQuery createDispatchQuery(Session session, String query, PreparedQuery preparedQuery, String slug, ResourceGroupId resourceGroup, ResourceGroupManager resourceGroupManager) {
WarningCollector warningCollector = warningCollectorFactory.create();
QueryStateMachine stateMachine = QueryStateMachine.begin(query, preparedQuery.getPrepareSql(), session, locationFactory.createQueryLocation(session.getQueryId()), resourceGroup, resourceGroupManager, isTransactionControlStatement(preparedQuery.getStatement()), transactionManager, accessControl, executor, metadata, warningCollector);
queryMonitor.queryCreatedEvent(stateMachine.getBasicQueryInfo(Optional.empty()));
ListenableFuture<QueryExecution> queryExecutionFuture = executor.submit(() -> {
stateMachine.beginSyntaxAnalysis();
QueryExecutionFactory<?> queryExecutionFactory = executionFactories.get(preparedQuery.getStatement().getClass());
if (queryExecutionFactory == null) {
throw new PrestoException(NOT_SUPPORTED, "Unsupported statement type: " + preparedQuery.getStatement().getClass().getSimpleName());
}
QueryExecution queryExecution = queryExecutionFactory.createQueryExecution(preparedQuery, stateMachine, slug, warningCollector);
stateMachine.endSyntaxAnalysis();
return queryExecution;
});
return new LocalDispatchQuery(stateMachine, queryExecutionFuture, clusterSizeMonitor, executor, queryManager::createQuery);
}
use of io.prestosql.execution.warnings.WarningCollector in project hetu-core by openlookeng.
the class StarTreeAggregationRule method optimize.
public Result optimize(AggregationNode aggregationNode, final PlanNode filterNode, TableScanNode tableScanNode, Map<String, Object> symbolMapping, Session session, PlanSymbolAllocator symbolAllocator, PlanNodeIdAllocator idAllocator, WarningCollector warningCollector) {
TableHandle tableHandle = tableScanNode.getTable();
TableMetadata tableMetadata = metadata.getTableMetadata(session, tableHandle);
String tableName = tableMetadata.getQualifiedName().toString();
CubeStatement statement = CubeStatementGenerator.generate(tableName, aggregationNode, symbolMapping);
// Don't use star-tree for non-aggregate queries
if (statement.getAggregations().isEmpty()) {
return Result.empty();
}
boolean hasDistinct = statement.getAggregations().stream().anyMatch(AggregationSignature::isDistinct);
// Since cube is pre-aggregated, utilising it for such queries could return incorrect result
if (aggregationNode.hasEmptyGroupingSet() && hasDistinct) {
return Result.empty();
}
List<CubeMetadata> cubeMetadataList = CubeMetadata.filter(this.cubeMetaStore.getMetadataList(statement.getFrom()), statement);
// Compare FilterNode predicate with Cube predicates to evaluate which cube can be used.
List<CubeMetadata> matchedCubeMetadataList = cubeMetadataList.stream().filter(cubeMetadata -> filterPredicateMatches((FilterNode) filterNode, cubeMetadata, session, symbolAllocator.getTypes())).collect(Collectors.toList());
// Match based on filter conditions
if (matchedCubeMetadataList.isEmpty()) {
return Result.empty();
}
LongSupplier lastModifiedTimeSupplier = metadata.getTableLastModifiedTimeSupplier(session, tableHandle);
if (lastModifiedTimeSupplier == null) {
warningCollector.add(new PrestoWarning(EXPIRED_CUBE, "Unable to identify last modified time of " + tableName + ". Ignoring star tree cubes."));
return Result.empty();
}
// Filter out cubes that were created before the source table was updated
long lastModifiedTime = lastModifiedTimeSupplier.getAsLong();
// There was a problem retrieving last modified time, we should skip using star tree rather than failing the query
if (lastModifiedTime == -1L) {
return Result.empty();
}
matchedCubeMetadataList = matchedCubeMetadataList.stream().filter(cubeMetadata -> cubeMetadata.getSourceTableLastUpdatedTime() >= lastModifiedTime).collect(Collectors.toList());
if (matchedCubeMetadataList.isEmpty()) {
warningCollector.add(new PrestoWarning(EXPIRED_CUBE, tableName + " has been modified after creating cubes. Ignoring expired cubes."));
return Result.empty();
}
// If multiple cubes are matching then lets select the recent built cube
// so sort the cube based on the last updated time stamp
matchedCubeMetadataList.sort(Comparator.comparingLong(CubeMetadata::getLastUpdatedTime).reversed());
CubeMetadata matchedCubeMetadata = matchedCubeMetadataList.get(0);
AggregationRewriteWithCube aggregationRewriteWithCube = new AggregationRewriteWithCube(metadata, session, symbolAllocator, idAllocator, symbolMapping, matchedCubeMetadata);
return Result.ofPlanNode(aggregationRewriteWithCube.rewrite(aggregationNode, rewriteByRemovingSourceFilter(filterNode, matchedCubeMetadata)));
}
use of io.prestosql.execution.warnings.WarningCollector in project hetu-core by openlookeng.
the class Analyzer method analyze.
public Analysis analyze(Statement statement, boolean isDescribe) {
Statement rewrittenStatement = StatementRewrite.rewrite(session, metadata, cubeManager, sqlParser, queryExplainer, statement, parameters, accessControl, warningCollector, heuristicIndexerManager);
Analysis analysis = new Analysis(rewrittenStatement, parameters, isDescribe);
analysis.setOriginalStatement(statement);
StatementAnalyzer analyzer = new StatementAnalyzer(analysis, metadata, sqlParser, accessControl, session, warningCollector, heuristicIndexerManager, cubeManager);
analyzer.analyze(rewrittenStatement, Optional.empty());
// check column access permissions for each table
analysis.getTableColumnReferences().forEach((accessControlInfo, tableColumnReferences) -> tableColumnReferences.forEach((tableName, columns) -> accessControlInfo.getAccessControl().checkCanSelectFromColumns(session.getRequiredTransactionId(), accessControlInfo.getIdentity(), tableName, columns)));
return analysis;
}
use of io.prestosql.execution.warnings.WarningCollector in project hetu-core by openlookeng.
the class CachedSqlQueryExecution method createPlan.
@Override
protected Plan createPlan(Analysis analysis, Session session, List<PlanOptimizer> planOptimizers, PlanNodeIdAllocator idAllocator, Metadata metadata, TypeAnalyzer typeAnalyzer, StatsCalculator statsCalculator, CostCalculator costCalculator, WarningCollector warningCollector) {
Statement statement = analysis.getStatement();
// Get relevant Session properties which may affect the resulting execution plan
// Property to property value mapping
Map<String, Object> systemSessionProperties = new HashMap<>();
SystemSessionProperties sessionProperties = new SystemSessionProperties();
for (PropertyMetadata<?> property : sessionProperties.getSessionProperties()) {
systemSessionProperties.put(property.getName(), session.getSystemProperty(property.getName(), property.getJavaType()));
}
// if the original statement before rewriting is CreateIndex, set session to let connector know that pageMetadata should be enabled
if (analysis.getOriginalStatement() instanceof CreateIndex || analysis.getOriginalStatement() instanceof UpdateIndex) {
session.setPageMetadataEnabled(true);
}
// build list of fully qualified table names
List<String> tableNames = new ArrayList<>();
Map<String, TableStatistics> tableStatistics = new HashMap<>();
// Get column name to column type to detect column type changes between queries more easily
Map<String, Type> columnTypes = new HashMap<>();
// Cacheable conditions:
// 1. Caching must be enabled globally
// 2. Caching must be enabled in the session
// 3. There must not be any parameters in the query
// TODO: remove requirement for empty params and implement parameter rewrite
// 4. Methods in ConnectorTableHandle and ConnectorMetadata must be
// overwritten to allow access to fully qualified table names and column names
// 5. Statement must be an instance of Query and not contain CurrentX functions
boolean cacheable = this.cache.isPresent() && isExecutionPlanCacheEnabled(session) && analysis.getParameters().isEmpty() && validateAndExtractTableAndColumns(analysis, metadata, session, tableNames, tableStatistics, columnTypes) && isCacheable(statement) && // create index and update index should not be cached
(!(analysis.getOriginalStatement() instanceof CreateIndex || analysis.getOriginalStatement() instanceof UpdateIndex));
cacheable = cacheable && !tableNames.isEmpty();
if (!cacheable) {
return super.createPlan(analysis, session, planOptimizers, idAllocator, metadata, typeAnalyzer, statsCalculator, costCalculator, warningCollector);
}
List<String> optimizers = new ArrayList<>();
// build list of enabled optimizers and rules for cache key
for (PlanOptimizer planOptimizer : planOptimizers) {
if (planOptimizer instanceof IterativeOptimizer) {
IterativeOptimizer iterativeOptimizer = (IterativeOptimizer) planOptimizer;
Set<Rule<?>> rules = iterativeOptimizer.getRules();
for (Rule rule : rules) {
if (OptimizerUtils.isEnabledRule(rule, session)) {
optimizers.add(rule.getClass().getSimpleName());
}
}
} else {
if (OptimizerUtils.isEnabledLegacy(planOptimizer, session)) {
optimizers.add(planOptimizer.getClass().getSimpleName());
}
}
}
Set<String> connectors = tableNames.stream().map(table -> table.substring(0, table.indexOf("."))).collect(Collectors.toSet());
connectors.stream().forEach(connector -> {
for (Map.Entry<String, String> property : session.getConnectorProperties(new CatalogName(connector)).entrySet()) {
systemSessionProperties.put(connector + "." + property.getKey(), property.getValue());
}
});
Plan plan;
// TODO: Traverse the statement to build the key then combine tables/optimizers.. etc
int key = SqlQueryExecutionCacheKeyGenerator.buildKey((Query) statement, tableNames, optimizers, columnTypes, session.getTimeZoneKey(), systemSessionProperties);
CachedSqlQueryExecutionPlan cachedPlan = this.cache.get().getIfPresent(key);
HetuLogicalPlanner logicalPlanner = new HetuLogicalPlanner(session, planOptimizers, idAllocator, metadata, typeAnalyzer, statsCalculator, costCalculator, warningCollector);
PlanNode root;
plan = cachedPlan != null ? cachedPlan.getPlan() : null;
// that rely on system time
if (plan != null && cachedPlan.getTimeZoneKey().equals(session.getTimeZoneKey()) && cachedPlan.getStatement().equals(statement) && session.getTransactionId().isPresent() && cachedPlan.getIdentity().getUser().equals(session.getIdentity().getUser())) {
// TODO: traverse the statement and accept partial match
root = plan.getRoot();
boolean isValidCachePlan = tablesMatch(root, analysis.getTables());
try {
if (!isEqualBasicStatistics(cachedPlan.getTableStatistics(), tableStatistics, tableNames) || !isValidCachePlan) {
for (TableHandle tableHandle : analysis.getTables()) {
tableStatistics.replace(tableHandle.getFullyQualifiedName(), metadata.getTableStatistics(session, tableHandle, Constraint.alwaysTrue(), true));
}
if (!cachedPlan.getTableStatistics().equals(tableStatistics) || !isValidCachePlan) {
// Table have changed, therfore the cached plan may no longer be applicable
throw new NoSuchElementException();
}
}
// TableScanNode may contain the old transaction id.
// The following logic rewrites the logical plan by replacing the TableScanNode with a new TableScanNode which
// contains the new transaction id from session.
root = SimplePlanRewriter.rewriteWith(new TableHandleRewriter(session, analysis, metadata), root);
} catch (NoSuchElementException e) {
// Cached plan is outdated
// invalidate cache
this.cache.get().invalidateAll();
// Build a new plan
plan = createAndCachePlan(key, logicalPlanner, statement, tableNames, tableStatistics, optimizers, analysis, columnTypes, systemSessionProperties);
root = plan.getRoot();
}
} else {
// Build a new plan
for (TableHandle tableHandle : analysis.getTables()) {
tableStatistics.replace(tableHandle.getFullyQualifiedName(), metadata.getTableStatistics(session, tableHandle, Constraint.alwaysTrue(), true));
}
plan = createAndCachePlan(key, logicalPlanner, statement, tableNames, tableStatistics, optimizers, analysis, columnTypes, systemSessionProperties);
root = plan.getRoot();
}
// BeginTableWrite optimizer must be run at the end as the last optimization
// due to a hack Hetu community added which also serves to updates
// metadata in the nodes
root = this.beginTableWrite.optimize(root, session, null, null, null, null);
plan = update(plan, root);
return plan;
}
Aggregations