Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Licensed 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.
  */
 package com.facebook.presto.sql.analyzer;
 
 
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_COLUMNS;
 import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_INTERNAL_FUNCTIONS;
 import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_INTERNAL_PARTITIONS;
 import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_SCHEMATA;
 import static com.facebook.presto.connector.informationSchema.InformationSchemaMetadata.TABLE_TABLES;
 import static com.facebook.presto.connector.system.CatalogSystemTable.CATALOG_TABLE_NAME;
 import static com.facebook.presto.spi.type.BigintType.BIGINT;
 import static com.facebook.presto.sql.QueryUtil.aliased;
 import static com.facebook.presto.sql.QueryUtil.aliasedName;
 import static com.facebook.presto.sql.QueryUtil.aliasedNullToEmpty;
 import static com.facebook.presto.sql.QueryUtil.aliasedYesNoToBoolean;
 import static com.facebook.presto.sql.QueryUtil.ascending;
 import static com.facebook.presto.sql.QueryUtil.caseWhen;
 import static com.facebook.presto.sql.QueryUtil.equal;
 import static com.facebook.presto.sql.QueryUtil.functionCall;
 import static com.facebook.presto.sql.QueryUtil.logicalAnd;
 import static com.facebook.presto.sql.QueryUtil.nameReference;
 import static com.facebook.presto.sql.QueryUtil.ordering;
 import static com.facebook.presto.sql.QueryUtil.row;
 import static com.facebook.presto.sql.QueryUtil.selectAll;
 import static com.facebook.presto.sql.QueryUtil.selectList;
 import static com.facebook.presto.sql.QueryUtil.simpleQuery;
 import static com.facebook.presto.sql.QueryUtil.subquery;
 import static com.facebook.presto.sql.QueryUtil.table;
 import static com.facebook.presto.sql.QueryUtil.unaliasedName;
 import static com.facebook.presto.sql.QueryUtil.values;
 import static com.facebook.presto.sql.analyzer.SemanticErrorCode.COLUMN_NAME_NOT_SPECIFIED;
 import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_COLUMN_NAME;
 import static com.facebook.presto.sql.analyzer.SemanticErrorCode.DUPLICATE_RELATION;
 import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_ORDINAL;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.INVALID_SCHEMA_NAME;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISMATCHED_SET_COLUMN_TYPES;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.MISSING_TABLE;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.NOT_SUPPORTED;
import static com.facebook.presto.sql.analyzer.SemanticErrorCode.TABLE_ALREADY_EXISTS;
import static com.facebook.presto.sql.tree.BooleanLiteral.FALSE_LITERAL;
import static com.facebook.presto.sql.tree.BooleanLiteral.TRUE_LITERAL;
import static com.facebook.presto.sql.tree.ExplainFormat.Type.TEXT;
import static com.facebook.presto.sql.tree.ExplainType.Type.LOGICAL;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.elementsEqual;
import static com.google.common.collect.Iterables.transform;
    private final Analysis analysis;
    private final Metadata metadata;
    private final Session session;
    private final Optional<QueryExplainerqueryExplainer;
    private final boolean experimentalSyntaxEnabled;
    private final SqlParser sqlParser;
    public StatementAnalyzer(
            Analysis analysis,
            Metadata metadata,
            SqlParser sqlParser,
            Session session,
            boolean experimentalSyntaxEnabled,
            Optional<QueryExplainerqueryExplainer)
    {
        this. = checkNotNull(analysis"analysis is null");
        this. = checkNotNull(metadata"metadata is null");
        this. = checkNotNull(sqlParser"sqlParser is null");
        this. = checkNotNull(session"session is null");
        this. = experimentalSyntaxEnabled;
        this. = checkNotNull(queryExplainer"queryExplainer is null");
    }
    @Override
    protected TupleDescriptor visitShowTables(ShowTables showTablesAnalysisContext context)
    {
        String catalogName = .getCatalog();
        String schemaName = .getSchema();
        Optional<QualifiedNameschema = showTables.getSchema();
        if (schema.isPresent()) {
            List<Stringparts = schema.get().getParts();
            if (parts.size() > 2) {
                throw new SemanticException(showTables"too many parts in schema name: %s"schema);
            }
            if (parts.size() == 2) {
                catalogName = parts.get(0);
            }
            schemaName = schema.get().getSuffix();
        }
        // TODO: throw SemanticException if schema does not exist
        Expression predicate = equal(nameReference("table_schema"), new StringLiteral(schemaName));
        Optional<StringlikePattern = showTables.getLikePattern();
        if (likePattern.isPresent()) {
            Expression likePredicate = new LikePredicate(nameReference("table_name"), new StringLiteral(likePattern.get()), null);
            predicate = logicalAnd(predicatelikePredicate);
        }
        Query query = simpleQuery(
                selectList(aliasedName("table_name""Table")),
                from(catalogName),
                predicate,
                ordering(ascending("table_name")));
        return process(querycontext);
    }
    @Override
    protected TupleDescriptor visitShowSchemas(ShowSchemas nodeAnalysisContext context)
    {
        Query query = simpleQuery(
                selectList(aliasedName("schema_name""Schema")),
                from(node.getCatalog().orElse(.getCatalog()), ),
                ordering(ascending("schema_name")));
        return process(querycontext);
    }
    @Override
    {
        Query query = simpleQuery(
                selectList(aliasedName("catalog_name""Catalog")),
                from(.getCatalog(), ),
                ordering(ascending("catalog_name")));
        return process(querycontext);
    }
    @Override
    protected TupleDescriptor visitShowColumns(ShowColumns showColumnsAnalysisContext context)
    {
        QualifiedTableName tableName = MetadataUtil.createQualifiedTableName(showColumns.getTable());
        if (!.getView(tableName).isPresent() &&
                !.getTableHandle(tableName).isPresent()) {
            throw new SemanticException(showColumns"Table '%s' does not exist"tableName);
        }
        Query query = simpleQuery(
                selectList(
                        aliasedName("column_name""Column"),
                        aliasedName("data_type""Type"),
                        aliasedYesNoToBoolean("is_nullable""Null"),
                        aliasedYesNoToBoolean("is_partition_key""Partition Key"),
                        aliasedNullToEmpty("comment""Comment")),
                from(tableName.getCatalogName(), ),
                logicalAnd(
                        equal(nameReference("table_schema"), new StringLiteral(tableName.getSchemaName())),
                        equal(nameReference("table_name"), new StringLiteral(tableName.getTableName()))),
                ordering(ascending("ordinal_position")));
        return process(querycontext);
    }
    @Override
    protected TupleDescriptor visitUse(Use nodeAnalysisContext context)
    {
        .setUpdateType("USE");
        throw new SemanticException(node"USE statement is not supported");
    }
    @Override
    protected TupleDescriptor visitShowPartitions(ShowPartitions showPartitionsAnalysisContext context)
    {
        QualifiedTableName table = MetadataUtil.createQualifiedTableName(showPartitions.getTable());
        Optional<TableHandletableHandle = .getTableHandle(table);
        if (!tableHandle.isPresent()) {
            throw new SemanticException(showPartitions"Table '%s' does not exist"table);
        }
            /*
                Generate a dynamic pivot to output one column per partition key.
                For example, a table with two partition keys (ds, cluster_name)
                would generate the following query:
                SELECT
                  partition_number
                , max(CASE WHEN partition_key = 'ds' THEN partition_value END) ds
                , max(CASE WHEN partition_key = 'cluster_name' THEN partition_value END) cluster_name
                FROM ...
                GROUP BY partition_number
                The values are also cast to the type of the partition column.
                The query is then wrapped to allow custom filtering and ordering.
            */
        ImmutableList.Builder<SelectItemselectList = ImmutableList.builder();
        ImmutableList.Builder<SelectItemwrappedList = ImmutableList.builder();
        selectList.add(unaliasedName("partition_number"));
        for (ColumnMetadata column : .getTableMetadata(tableHandle.get()).getColumns()) {
            if (!column.isPartitionKey()) {
                continue;
            }
            Expression key = equal(nameReference("partition_key"), new StringLiteral(column.getName()));
            Expression value = caseWhen(keynameReference("partition_value"));
            value = new Cast(valuecolumn.getType().getTypeSignature().toString());
            Expression function = functionCall("max"value);
            selectList.add(new SingleColumn(functioncolumn.getName()));
            wrappedList.add(unaliasedName(column.getName()));
        }
        Query query = simpleQuery(
                selectAll(selectList.build()),
                from(table.getCatalogName(), ),
                Optional.of(logicalAnd(
                        equal(nameReference("table_schema"), new StringLiteral(table.getSchemaName())),
                        equal(nameReference("table_name"), new StringLiteral(table.getTableName())))),
                ImmutableList.of(nameReference("partition_number")),
                Optional.empty(),
                ImmutableList.of(),
                Optional.empty());
        query = simpleQuery(
                selectAll(wrappedList.build()),
                subquery(query),
                showPartitions.getWhere(),
                ImmutableList.of(),
                Optional.empty(),
                ImmutableList.<SortItem>builder()
                        .addAll(showPartitions.getOrderBy())
                        .add(ascending("partition_number"))
                        .build(),
                showPartitions.getLimit());
        return process(querycontext);
    }
    @Override
    {
        Query query = simpleQuery(selectList(
                        aliasedName("function_name""Function"),
                        aliasedName("return_type""Return Type"),
                        aliasedName("argument_types""Argument Types"),
                        aliasedName("function_type""Function Type"),
                        aliasedName("deterministic""Deterministic"),
                        aliasedName("description""Description")),
                from(.getCatalog(), ),
                ordering(
                        ascending("function_name"),
                        ascending("return_type"),
                        ascending("argument_types"),
                        ascending("function_type")));
        return process(querycontext);
    }
    @Override
    protected TupleDescriptor visitShowSession(ShowSession nodeAnalysisContext context)
    {
        ImmutableList.Builder<Expressionrows = ImmutableList.builder();
        for (Entry<StringStringproperty : new TreeMap<>(.getSystemProperties()).entrySet()) {
            rows.add(row(
                    new StringLiteral(property.getKey()),
                    new StringLiteral(property.getValue()),
                    ));
        }
        for (Entry<StringMap<StringString>> entry : new TreeMap<>(.getCatalogProperties()).entrySet()) {
            String catalog = entry.getKey();
            for (Entry<StringStringproperty : new TreeMap<>(entry.getValue()).entrySet()) {
                rows.add(row(
                        new StringLiteral(catalog + "." + property.getKey()),
                        new StringLiteral(property.getValue()),
                        ));
            }
        }
        // add bogus row so we can support empty sessions
        rows.add(row(new StringLiteral(""), new StringLiteral(""), ));
        Query query = simpleQuery(
                selectList(
                        aliasedName("name""Name"),
                        aliasedName("value""Value")),
                aliased(
                        new Values(rows.build()),
                        "session",
                        ImmutableList.of("name""value""include")),
                nameReference("include"));
        return process(querycontext);
    }
    @Override
    protected TupleDescriptor visitInsert(Insert insertAnalysisContext context)
    {
        .setUpdateType("INSERT");
        // analyze the query that creates the data
        TupleDescriptor descriptor = process(insert.getQuery(), context);
        // verify the insert destination columns match the query
        QualifiedTableName targetTable = MetadataUtil.createQualifiedTableName(insert.getTarget());
        Optional<TableHandletargetTableHandle = .getTableHandle(targetTable);
        if (!targetTableHandle.isPresent()) {
            throw new SemanticException(insert"Table '%s' does not exist"targetTable);
        }
        .setInsertTarget(targetTableHandle.get());
        List<ColumnMetadatacolumns = .getTableMetadata(targetTableHandle.get()).getColumns();
        Iterable<TypetableTypes = FluentIterable.from(columns)
                .filter(column -> !column.isHidden())
                .transform(ColumnMetadata::getType);
        Iterable<TypequeryTypes = transform(descriptor.getVisibleFields(), Field::getType);
        if (!elementsEqual(tableTypesqueryTypes)) {
            throw new SemanticException(insert"Insert query has mismatched column types: " +
                    "Table: (" + Joiner.on(", ").join(tableTypes) + "), " +
                    "Query: (" + Joiner.on(", ").join(queryTypes) + ")");
        }
        return new TupleDescriptor(Field.newUnqualified("rows"));
    }
    @Override
    protected TupleDescriptor visitCreateTable(CreateTable nodeAnalysisContext context)
    {
        .setUpdateType("CREATE TABLE");
        // turn this into a query that has a new table writer node on top.
        QualifiedTableName targetTable = MetadataUtil.createQualifiedTableName(node.getName());
        .setCreateTableDestination(targetTable);
        Optional<TableHandletargetTableHandle = .getTableHandle(targetTable);
        if (targetTableHandle.isPresent()) {
            throw new SemanticException(node"Destination table '%s' already exists"targetTable);
        }
        // analyze the query that creates the table
        TupleDescriptor descriptor = process(node.getQuery(), context);
        validateColumnNames(nodedescriptor);
        return new TupleDescriptor(Field.newUnqualified("rows"));
    }
    @Override
    protected TupleDescriptor visitCreateView(CreateView nodeAnalysisContext context)
    {
        .setUpdateType("CREATE VIEW");
        // analyze the query that creates the view
        TupleDescriptor descriptor = process(node.getQuery(), context);
        validateColumnNames(nodedescriptor);
        return descriptor;
    }
    private static void validateColumnNames(Statement nodeTupleDescriptor descriptor)
    {
        // verify that all column names are specified and unique
        // TODO: collect errors and return them all at once
        Set<Stringnames = new HashSet<>();
        for (Field field : descriptor.getVisibleFields()) {
            Optional<StringfieldName = field.getName();
            if (!fieldName.isPresent()) {
                throw new SemanticException(node"Column name not specified at position %s"descriptor.indexOf(field) + 1);
            }
            if (!names.add(fieldName.get())) {
                throw new SemanticException(node"Column name '%s' specified more than once"fieldName.get());
            }
        }
    }
    @Override
    protected TupleDescriptor visitExplain(Explain nodeAnalysisContext context)
            throws SemanticException
    {
        checkState(.isPresent(), "query explainer not available");
        ExplainType.Type planType = ;
        ExplainFormat.Type planFormat = ;
        List<ExplainOptionoptions = node.getOptions();
        for (ExplainOption option : options) {
            if (option instanceof ExplainType) {
                planType = ((ExplainTypeoption).getType();
                break;
            }
        }
        for (ExplainOption option : options) {
            if (option instanceof ExplainFormat) {
                planFormat = ((ExplainFormatoption).getType();
                break;
            }
        }
        String queryPlan = getQueryPlan(nodeplanTypeplanFormat);
        Query query = simpleQuery(
                selectList(new AllColumns()),
                aliased(
                        values(row(new StringLiteral((queryPlan)))),
                        "plan",
                        ImmutableList.of("Query Plan")));
        return process(querycontext);
    }
    private String getQueryPlan(Explain nodeExplainType.Type planTypeExplainFormat.Type planFormat)
            throws IllegalArgumentException
    {
        switch (planFormat) {
            case :
                return .get().getGraphvizPlan(node.getStatement(), planType);
            case :
                return .get().getPlan(node.getStatement(), planType);
            case :
                // ignore planType if planFormat is JSON
                return .get().getJsonPlan(node.getStatement());
        }
        throw new IllegalArgumentException("Invalid Explain Format: " + planFormat.toString());
    }
    @Override
    protected TupleDescriptor visitQuery(Query nodeAnalysisContext parentContext)
    {
        AnalysisContext context = new AnalysisContext(parentContext);
        if (node.getApproximate().isPresent()) {
            if (!) {
                throw new SemanticException(node"approximate queries are not enabled");
            }
            context.setApproximate(true);
        }
        analyzeWith(nodecontext);
        TupleDescriptor descriptor = analyzer.process(node.getQueryBody(), context);
        analyzeOrderBy(nodedescriptorcontext);
        // Input fields == Output fields
        .setOutputDescriptor(nodedescriptor);
        .setOutputExpressions(nodedescriptorToFields(descriptor));
        .setQuery(node);
        return descriptor;
    }
    private static List<FieldOrExpressiondescriptorToFields(TupleDescriptor tupleDescriptor)
    {
        ImmutableList.Builder<FieldOrExpressionbuilder = ImmutableList.builder();
        for (int fieldIndex = 0; fieldIndex < tupleDescriptor.getAllFieldCount(); fieldIndex++) {
            builder.add(new FieldOrExpression(fieldIndex));
        }
        return builder.build();
    }
    private void analyzeWith(Query nodeAnalysisContext context)
    {
        // analyze WITH clause
        if (!node.getWith().isPresent()) {
            return;
        }
        With with = node.getWith().get();
        if (with.isRecursive()) {
            throw new SemanticException(with"Recursive WITH queries are not supported");
        }
        for (WithQuery withQuery : with.getQueries()) {
            if (withQuery.getColumnNames() != null && !withQuery.getColumnNames().isEmpty()) {
                throw new SemanticException(withQuery"Column alias not supported in WITH queries");
            }
            Query query = withQuery.getQuery();
            process(querycontext);
            String name = withQuery.getName();
            if (context.isNamedQueryDeclared(name)) {
                throw new SemanticException(withQuery"WITH query name '%s' specified more than once"name);
            }
            context.addNamedQuery(namequery);
        }
    }
    private void analyzeOrderBy(Query nodeTupleDescriptor tupleDescriptorAnalysisContext context)
    {
        List<SortItemitems = node.getOrderBy();
        ImmutableList.Builder<FieldOrExpressionorderByFieldsBuilder = ImmutableList.builder();
        if (!items.isEmpty()) {
            for (SortItem item : items) {
                Expression expression = item.getSortKey();
                FieldOrExpression orderByField;
                if (expression instanceof LongLiteral) {
                    // this is an ordinal in the output tuple
                    long ordinal = ((LongLiteralexpression).getValue();
                    if (ordinal < 1 || ordinal > tupleDescriptor.getVisibleFieldCount()) {
                        throw new SemanticException(expression"ORDER BY position %s is not in select list"ordinal);
                    }
                    orderByField = new FieldOrExpression(Ints.checkedCast(ordinal - 1));
                }
                else {
                    // otherwise, just use the expression as is
                    orderByField = new FieldOrExpression(expression);
                    ExpressionAnalysis expressionAnalysis = ExpressionAnalyzer.analyzeExpression(,
                            ,
                            ,
                            tupleDescriptor,
                            ,
                            ,
                            context,
                            orderByField.getExpression());
                    .addInPredicates(nodeexpressionAnalysis.getSubqueryInPredicates());
                }
                orderByFieldsBuilder.add(orderByField);
            }
        }
        .setOrderByExpressions(nodeorderByFieldsBuilder.build());
    }
    private static Relation from(String catalogSchemaTableName table)
    {
        return table(QualifiedName.of(catalogtable.getSchemaName(), table.getTableName()));
    }
New to GrepCode? Check out our FAQ X