package com.airbnb.airpal.core.execution; import com.airbnb.airpal.presto.Table; import com.facebook.presto.sql.tree.CreateTable; import com.facebook.presto.sql.tree.CreateView; import com.facebook.presto.sql.tree.DefaultTraversalVisitor; import com.facebook.presto.sql.tree.DropTable; import com.facebook.presto.sql.tree.DropView; import com.facebook.presto.sql.tree.Join; import com.facebook.presto.sql.tree.JoinOn; import com.facebook.presto.sql.tree.Node; import com.facebook.presto.sql.tree.QualifiedName; import com.facebook.presto.sql.tree.RenameTable; import com.facebook.presto.sql.tree.Use; import com.facebook.presto.sql.tree.WithQuery; import com.google.common.collect.Sets; import lombok.EqualsAndHashCode; import lombok.Value; import java.util.HashSet; import java.util.List; import java.util.Set; @Value @EqualsAndHashCode(callSuper = false) public class InputReferenceExtractor extends DefaultTraversalVisitor<InputReferenceExtractor.CatalogSchemaContext, InputReferenceExtractor.CatalogSchemaContext> { private final Set<Table> references = new HashSet<>(); private final Set<Table> aliases = new HashSet<>(); public Set<Table> getReferences() { return Sets.difference(references, aliases); } private Table qualifiedNameToTable(QualifiedName name, CatalogSchemaContext context) { List<String> nameParts = name.getParts(); String connectorId = context.getCatalog(); String schema = context.getSchema(); String table = null; if (nameParts.size() == 3) { connectorId = nameParts.get(0); schema = nameParts.get(1); table = nameParts.get(2); } else if (nameParts.size() == 2) { schema = nameParts.get(0); table = nameParts.get(1); } else if (nameParts.size() == 1) { table = nameParts.get(0); } return new Table(connectorId, schema, table); } @Override protected CatalogSchemaContext visitCreateView(CreateView node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getName(), context)); visitQuery(node.getQuery(), context); return context; } @Override protected CatalogSchemaContext visitCreateTable(CreateTable node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getName(), context)); visitCreateTable(node, context); return context; } @Override protected CatalogSchemaContext visitDropTable(DropTable node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getTableName(), context)); return context; } @Override protected CatalogSchemaContext visitDropView(DropView node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getName(), context)); return context; } @Override protected CatalogSchemaContext visitTable(com.facebook.presto.sql.tree.Table node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getName(), context)); return context; } @Override protected CatalogSchemaContext visitRenameTable(RenameTable node, CatalogSchemaContext context) { references.add(qualifiedNameToTable(node.getSource(), context)); return context; } @Override protected CatalogSchemaContext visitWithQuery(WithQuery node, CatalogSchemaContext context) { aliases.add(new Table(context.getCatalog(), context.getSchema(), node.getName())); return super.visitWithQuery(node, context); } @Override protected CatalogSchemaContext visitUse(Use node, CatalogSchemaContext context) { return new CatalogSchemaContext(node.getCatalog().orElse(context.getCatalog()), node.getSchema()); } @Override protected CatalogSchemaContext visitNode(Node node, CatalogSchemaContext context) { return context; } @Override protected CatalogSchemaContext visitJoin(Join node, CatalogSchemaContext context) { process(node.getLeft(), context); process(node.getRight(), context); if (node.getCriteria().isPresent()) { if (node.getCriteria().get() instanceof JoinOn) { process(((JoinOn) node.getCriteria().get()).getExpression(), context); } } return context; } @Value public static class CatalogSchemaContext { private final String catalog; private final String schema; } }