/*
* Licensed to CRATE Technology GmbH ("Crate") under one or more contributor
* license agreements. See the NOTICE file distributed with this work for
* additional information regarding copyright ownership. Crate licenses
* this file to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may
* obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* However, if you have executed another commercial license agreement
* with Crate these terms will supersede the license and you may use the
* software solely pursuant to the terms of the relevant commercial agreement.
*/
package io.crate.analyze;
import io.crate.action.sql.SessionContext;
import io.crate.analyze.relations.AnalyzedRelation;
import io.crate.analyze.relations.QueriedRelation;
import io.crate.analyze.relations.RelationAnalyzer;
import io.crate.analyze.repositories.RepositoryParamValidator;
import io.crate.executor.transport.RepositoryService;
import io.crate.metadata.FulltextAnalyzerResolver;
import io.crate.metadata.Functions;
import io.crate.metadata.Schemas;
import io.crate.sql.tree.*;
import org.elasticsearch.cluster.service.ClusterService;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.Singleton;
import org.elasticsearch.index.analysis.AnalysisRegistry;
import java.util.Locale;
@Singleton
public class Analyzer {
private final AnalyzerDispatcher dispatcher = new AnalyzerDispatcher();
private final RelationAnalyzer relationAnalyzer;
private final DropTableAnalyzer dropTableAnalyzer;
private final CreateTableStatementAnalyzer createTableStatementAnalyzer;
private final ShowCreateTableAnalyzer showCreateTableAnalyzer;
private final ExplainStatementAnalyzer explainStatementAnalyzer;
private final ShowStatementAnalyzer showStatementAnalyzer;
private final CreateBlobTableAnalyzer createBlobTableAnalyzer;
private final CreateAnalyzerStatementAnalyzer createAnalyzerStatementAnalyzer;
private final DropBlobTableAnalyzer dropBlobTableAnalyzer;
private final RefreshTableAnalyzer refreshTableAnalyzer;
private final OptimizeTableAnalyzer optimizeTableAnalyzer;
private final AlterTableAnalyzer alterTableAnalyzer;
private final AlterBlobTableAnalyzer alterBlobTableAnalyzer;
private final AlterTableAddColumnAnalyzer alterTableAddColumnAnalyzer;
private final InsertFromValuesAnalyzer insertFromValuesAnalyzer;
private final InsertFromSubQueryAnalyzer insertFromSubQueryAnalyzer;
private final CopyAnalyzer copyAnalyzer;
private final UpdateAnalyzer updateAnalyzer;
private final DeleteAnalyzer deleteAnalyzer;
private final DropRepositoryAnalyzer dropRepositoryAnalyzer;
private final CreateRepositoryAnalyzer createRepositoryAnalyzer;
private final DropSnapshotAnalyzer dropSnapshotAnalyzer;
private final CreateSnapshotAnalyzer createSnapshotAnalyzer;
private final RestoreSnapshotAnalyzer restoreSnapshotAnalyzer;
private final UnboundAnalyzer unboundAnalyzer;
private final CreateFunctionAnalyzer createFunctionAnalyzer;
private final DropFunctionAnalyzer dropFunctionAnalyzer;
@Inject
public Analyzer(Schemas schemas,
Functions functions,
ClusterService clusterService,
AnalysisRegistry analysisRegistry,
RepositoryService repositoryService,
RepositoryParamValidator repositoryParamValidator) {
NumberOfShards numberOfShards = new NumberOfShards(clusterService);
this.relationAnalyzer = new RelationAnalyzer(clusterService, functions, schemas);
this.dropTableAnalyzer = new DropTableAnalyzer(schemas);
this.dropBlobTableAnalyzer = new DropBlobTableAnalyzer(schemas);
FulltextAnalyzerResolver fulltextAnalyzerResolver =
new FulltextAnalyzerResolver(clusterService, analysisRegistry);
this.createTableStatementAnalyzer = new CreateTableStatementAnalyzer(
schemas,
fulltextAnalyzerResolver,
functions,
numberOfShards
);
this.showCreateTableAnalyzer = new ShowCreateTableAnalyzer(schemas);
this.explainStatementAnalyzer = new ExplainStatementAnalyzer(this);
this.showStatementAnalyzer = new ShowStatementAnalyzer(this);
this.unboundAnalyzer = new UnboundAnalyzer(relationAnalyzer, showCreateTableAnalyzer, showStatementAnalyzer);
this.createBlobTableAnalyzer = new CreateBlobTableAnalyzer(schemas, numberOfShards);
this.createAnalyzerStatementAnalyzer = new CreateAnalyzerStatementAnalyzer(fulltextAnalyzerResolver);
this.refreshTableAnalyzer = new RefreshTableAnalyzer(schemas);
this.optimizeTableAnalyzer = new OptimizeTableAnalyzer(schemas);
this.alterTableAnalyzer = new AlterTableAnalyzer(schemas);
this.alterBlobTableAnalyzer = new AlterBlobTableAnalyzer(schemas);
this.alterTableAddColumnAnalyzer = new AlterTableAddColumnAnalyzer(schemas , fulltextAnalyzerResolver, functions);
this.insertFromValuesAnalyzer = new InsertFromValuesAnalyzer(functions, schemas);
this.insertFromSubQueryAnalyzer = new InsertFromSubQueryAnalyzer(functions, schemas, relationAnalyzer);
this.copyAnalyzer = new CopyAnalyzer(schemas, functions);
this.updateAnalyzer = new UpdateAnalyzer(schemas, functions, relationAnalyzer);
this.deleteAnalyzer = new DeleteAnalyzer(functions, relationAnalyzer);
this.dropRepositoryAnalyzer = new DropRepositoryAnalyzer(repositoryService);
this.createRepositoryAnalyzer = new CreateRepositoryAnalyzer(repositoryService, repositoryParamValidator);
this.dropSnapshotAnalyzer = new DropSnapshotAnalyzer(repositoryService);
this.createSnapshotAnalyzer = new CreateSnapshotAnalyzer(repositoryService, schemas);
this.restoreSnapshotAnalyzer = new RestoreSnapshotAnalyzer(repositoryService, schemas);
this.createFunctionAnalyzer = new CreateFunctionAnalyzer();
this.dropFunctionAnalyzer = new DropFunctionAnalyzer();
}
public Analysis boundAnalyze(Statement statement, SessionContext sessionContext, ParameterContext parameterContext) {
Analysis analysis = new Analysis(sessionContext, parameterContext, ParamTypeHints.EMPTY);
AnalyzedStatement analyzedStatement = analyzedStatement(statement, analysis);
analysis.analyzedStatement(analyzedStatement);
return analysis;
}
public AnalyzedRelation unboundAnalyze(Statement statement, SessionContext sessionContext, ParamTypeHints paramTypeHints) {
return unboundAnalyzer.analyze(statement, sessionContext, paramTypeHints);
}
AnalyzedStatement analyzedStatement(Statement statement, Analysis analysis) {
AnalyzedStatement analyzedStatement = dispatcher.process(statement, analysis);
assert analyzedStatement != null : "analyzed statement must not be null";
return analyzedStatement;
}
private class AnalyzerDispatcher extends AstVisitor<AnalyzedStatement, Analysis> {
@Override
protected AnalyzedStatement visitQuery(Query node, Analysis analysis) {
AnalyzedRelation relation = relationAnalyzer.analyze(node.getQueryBody(), analysis);
analysis.rootRelation(relation);
return new SelectAnalyzedStatement((QueriedRelation) relation);
}
@Override
public AnalyzedStatement visitDelete(Delete node, Analysis context) {
return deleteAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitInsertFromValues(InsertFromValues node, Analysis context) {
return insertFromValuesAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitInsertFromSubquery(InsertFromSubquery node, Analysis context) {
return insertFromSubQueryAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitUpdate(Update node, Analysis context) {
return updateAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitCopyFrom(CopyFrom node, Analysis context) {
return copyAnalyzer.convertCopyFrom(node, context);
}
@Override
public AnalyzedStatement visitCopyTo(CopyTo node, Analysis context) {
return copyAnalyzer.convertCopyTo(node, context);
}
@Override
public AnalyzedStatement visitDropTable(DropTable node, Analysis context) {
return dropTableAnalyzer.analyze(node, context.sessionContext().defaultSchema());
}
@Override
public AnalyzedStatement visitCreateTable(CreateTable node, Analysis analysis) {
return createTableStatementAnalyzer.analyze(node, analysis.parameterContext(), analysis.sessionContext());
}
public AnalyzedStatement visitShowCreateTable(ShowCreateTable node, Analysis analysis) {
ShowCreateTableAnalyzedStatement showCreateTableStatement =
showCreateTableAnalyzer.analyze(node.table(), analysis.sessionContext().defaultSchema());
analysis.rootRelation(showCreateTableStatement);
return showCreateTableStatement;
}
public AnalyzedStatement visitShowSchemas(ShowSchemas node, Analysis analysis) {
return showStatementAnalyzer.analyze(node, analysis);
}
@Override
public AnalyzedStatement visitShowTransaction(ShowTransaction showTransaction, Analysis context) {
return showStatementAnalyzer.analyzeShowTransaction(context);
}
public AnalyzedStatement visitShowTables(ShowTables node, Analysis analysis) {
return showStatementAnalyzer.analyze(node, analysis);
}
@Override
protected AnalyzedStatement visitShowColumns(ShowColumns node, Analysis context) {
return showStatementAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitCreateAnalyzer(CreateAnalyzer node, Analysis context) {
return createAnalyzerStatementAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitCreateBlobTable(CreateBlobTable node, Analysis context) {
return createBlobTableAnalyzer.analyze(node, context.parameterContext());
}
@Override
public AnalyzedStatement visitDropBlobTable(DropBlobTable node, Analysis context) {
return dropBlobTableAnalyzer.analyze(node);
}
@Override
public AnalyzedStatement visitAlterBlobTable(AlterBlobTable node, Analysis context) {
return alterBlobTableAnalyzer.analyze(node, context.parameterContext().parameters());
}
@Override
public AnalyzedStatement visitRefreshStatement(RefreshStatement node, Analysis context) {
return refreshTableAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitOptimizeStatement(OptimizeStatement node, Analysis context) {
return optimizeTableAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitAlterTable(AlterTable node, Analysis context) {
return alterTableAnalyzer.analyze(
node, context.parameterContext().parameters(), context.sessionContext().defaultSchema());
}
@Override
public AnalyzedStatement visitAlterTableAddColumnStatement(AlterTableAddColumn node, Analysis context) {
return alterTableAddColumnAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitSetStatement(SetStatement node, Analysis context) {
return SetStatementAnalyzer.analyze(node);
}
@Override
public AnalyzedStatement visitResetStatement(ResetStatement node, Analysis context) {
return SetStatementAnalyzer.analyze(node);
}
@Override
public AnalyzedStatement visitKillStatement(KillStatement node, Analysis context) {
return KillAnalyzer.analyze(node, context.parameterContext());
}
@Override
public AnalyzedStatement visitDropRepository(DropRepository node, Analysis context) {
return dropRepositoryAnalyzer.analyze(node);
}
@Override
public AnalyzedStatement visitCreateRepository(CreateRepository node, Analysis context) {
return createRepositoryAnalyzer.analyze(node, context.parameterContext());
}
@Override
public AnalyzedStatement visitCreateFunction(CreateFunction node, Analysis context) {
return createFunctionAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitDropFunction(DropFunction node, Analysis context) {
return dropFunctionAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitDropSnapshot(DropSnapshot node, Analysis context) {
return dropSnapshotAnalyzer.analyze(node);
}
@Override
public AnalyzedStatement visitCreateSnapshot(CreateSnapshot node, Analysis context) {
return createSnapshotAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitRestoreSnapshot(RestoreSnapshot node, Analysis context) {
return restoreSnapshotAnalyzer.analyze(node, context);
}
@Override
protected AnalyzedStatement visitExplain(Explain node, Analysis context) {
return explainStatementAnalyzer.analyze(node, context);
}
@Override
public AnalyzedStatement visitBegin(BeginStatement node, Analysis context) {
return new AnalyzedBegin();
}
@Override
protected AnalyzedStatement visitNode(Node node, Analysis context) {
throw new UnsupportedOperationException(String.format(Locale.ENGLISH, "cannot analyze statement: '%s'", node));
}
}
}