All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scalar.db.sql.CommandStatementExecutor Maven / Gradle / Ivy

The newest version!
package com.scalar.db.sql;

import com.google.common.annotations.VisibleForTesting;
import com.scalar.db.io.BooleanColumn;
import com.scalar.db.io.Column;
import com.scalar.db.io.TextColumn;
import com.scalar.db.sql.common.ColumnDefinitionsBuilder;
import com.scalar.db.sql.common.ColumnsRecord;
import com.scalar.db.sql.common.EmptyResultSet;
import com.scalar.db.sql.common.RecordsResultSet;
import com.scalar.db.sql.common.SingleColumnRecord;
import com.scalar.db.sql.common.SingleRecordResultSet;
import com.scalar.db.sql.common.SqlError;
import com.scalar.db.sql.metadata.Metadata;
import com.scalar.db.sql.metadata.NamespaceMetadata;
import com.scalar.db.sql.metadata.TableMetadata;
import com.scalar.db.sql.metadata.UserMetadata;
import com.scalar.db.sql.statement.AbortStatement;
import com.scalar.db.sql.statement.BeginStatement;
import com.scalar.db.sql.statement.CommandStatement;
import com.scalar.db.sql.statement.CommandStatementVisitor;
import com.scalar.db.sql.statement.CommitStatement;
import com.scalar.db.sql.statement.DescribeStatement;
import com.scalar.db.sql.statement.JoinStatement;
import com.scalar.db.sql.statement.PrepareStatement;
import com.scalar.db.sql.statement.ResumeStatement;
import com.scalar.db.sql.statement.RollbackStatement;
import com.scalar.db.sql.statement.SetModeStatement;
import com.scalar.db.sql.statement.ShowGrantsStatement;
import com.scalar.db.sql.statement.ShowNamespacesStatement;
import com.scalar.db.sql.statement.ShowTablesStatement;
import com.scalar.db.sql.statement.ShowUsersStatement;
import com.scalar.db.sql.statement.StartTransactionStatement;
import com.scalar.db.sql.statement.SuspendStatement;
import com.scalar.db.sql.statement.UseStatement;
import com.scalar.db.sql.statement.ValidateStatement;
import com.scalar.db.sql.util.SqlUtils;
import com.scalar.db.util.ScalarDbUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public class CommandStatementExecutor implements CommandStatementVisitor {

  private final CommandStatementValidator commandStatementValidator;

  CommandStatementExecutor() {
    commandStatementValidator = new CommandStatementValidator();
  }

  @VisibleForTesting
  CommandStatementExecutor(CommandStatementValidator commandStatementValidator) {
    this.commandStatementValidator = Objects.requireNonNull(commandStatementValidator);
  }

  public ResultSet execute(CommandStatement commandStatement, SqlSession sqlSession) {
    CommandStatement statement =
        SqlUtils.setNamespaceNameIfOmitted(
            commandStatement, sqlSession.getDefaultNamespaceName().orElse(null));
    commandStatementValidator.validate(statement);
    return statement.accept(this, sqlSession);
  }

  @Override
  public ResultSet visit(BeginStatement statement, SqlSession sqlSession) {
    sqlSession.begin();
    return createResultSetWithCurrentTransactionId(sqlSession);
  }

  @Override
  public ResultSet visit(StartTransactionStatement statement, SqlSession sqlSession) {
    sqlSession.start();
    return createResultSetWithCurrentTransactionId(sqlSession);
  }

  private ResultSet createResultSetWithCurrentTransactionId(SqlSession sqlSession) {
    Optional transactionId = sqlSession.getTransactionId();
    assert transactionId.isPresent();
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder().add("transactionId", DataType.TEXT).build();
    return new SingleRecordResultSet(
        new SingleColumnRecord(
            TextColumn.of("transactionId", transactionId.get()), columnDefinitions),
        columnDefinitions);
  }

  @Override
  public ResultSet visit(JoinStatement statement, SqlSession sqlSession) {
    sqlSession.join(statement.transactionId);
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(SuspendStatement statement, SqlSession sqlSession) {
    sqlSession.suspend();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(ResumeStatement statement, SqlSession sqlSession) {
    sqlSession.resume(statement.transactionId);
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(PrepareStatement statement, SqlSession sqlSession) {
    sqlSession.prepare();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(ValidateStatement statement, SqlSession sqlSession) {
    sqlSession.validate();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(CommitStatement statement, SqlSession sqlSession) {
    sqlSession.commit();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(RollbackStatement statement, SqlSession sqlSession) {
    sqlSession.rollback();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(AbortStatement statement, SqlSession sqlSession) {
    sqlSession.abort();
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(UseStatement statement, SqlSession sqlSession) {
    sqlSession.setDefaultNamespaceName(statement.namespaceName);
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(SetModeStatement statement, SqlSession sqlSession) {
    sqlSession.setTransactionMode(statement.transactionMode);
    return EmptyResultSet.INSTANCE;
  }

  @Override
  public ResultSet visit(ShowNamespacesStatement statement, SqlSession sqlSession) {
    Map namespaces = sqlSession.getMetadata().getNamespaces();
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder().add("namespaceName", DataType.TEXT).build();

    return new RecordsResultSet(
        namespaces.keySet().stream()
            .sorted()
            .map(
                n ->
                    (Record)
                        new SingleColumnRecord(
                            TextColumn.of("namespaceName", n), columnDefinitions))
            .iterator(),
        columnDefinitions);
  }

  @Override
  public ResultSet visit(ShowTablesStatement statement, SqlSession sqlSession) {
    NamespaceMetadata namespaceMetadata =
        sqlSession
            .getMetadata()
            .getNamespace(statement.namespaceName)
            .orElseThrow(
                () -> new IllegalArgumentException("Unknown namespace " + statement.namespaceName));
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder().add("tableName", DataType.TEXT).build();

    return new RecordsResultSet(
        namespaceMetadata.getTables().keySet().stream()
            .sorted()
            .map(
                t ->
                    (Record)
                        new SingleColumnRecord(TextColumn.of("tableName", t), columnDefinitions))
            .iterator(),
        columnDefinitions);
  }

  @Override
  public ResultSet visit(DescribeStatement statement, SqlSession sqlSession) {
    TableMetadata tableMetadata =
        SqlUtils.getTableMetadata(sqlSession.getMetadata(), statement.table);
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder()
            .add("columnName", DataType.TEXT)
            .add("type", DataType.TEXT)
            .add("isPrimaryKey", DataType.BOOLEAN)
            .add("isPartitionKey", DataType.BOOLEAN)
            .add("isClusteringKey", DataType.BOOLEAN)
            .add("clusteringOrder", DataType.TEXT)
            .add("isIndexed", DataType.BOOLEAN)
            .add("isEncrypted", DataType.BOOLEAN)
            .build();

    return new RecordsResultSet(
        tableMetadata.getColumns().values().stream()
            .map(
                c -> {
                  List> columns = new ArrayList<>();
                  columns.add(TextColumn.of("columnName", c.getName()));
                  columns.add(TextColumn.of("type", c.getDataType().name()));
                  columns.add(
                      BooleanColumn.of(
                          "isPrimaryKey", tableMetadata.isPrimaryKeyColumn(c.getName())));
                  columns.add(
                      BooleanColumn.of(
                          "isPartitionKey", tableMetadata.isPartitionKeyColumn(c.getName())));

                  boolean isClusteringKeyColumn = tableMetadata.isClusteringKeyColumn(c.getName());
                  columns.add(BooleanColumn.of("isClusteringKey", isClusteringKeyColumn));

                  if (isClusteringKeyColumn) {
                    columns.add(
                        TextColumn.of(
                            "clusteringOrder", tableMetadata.getClusteringKey().get(c).name()));
                  } else {
                    columns.add(TextColumn.ofNull("clusteringOrder"));
                  }

                  columns.add(
                      BooleanColumn.of(
                          "isIndexed", tableMetadata.getIndex(c.getName()).isPresent()));
                  columns.add(BooleanColumn.of("isEncrypted", c.isEncrypted()));

                  return (Record) new ColumnsRecord(columns, columnDefinitions);
                })
            .iterator(),
        columnDefinitions);
  }

  @Override
  public ResultSet visit(ShowUsersStatement statement, SqlSession sqlSession) {
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder()
            .add("username", DataType.TEXT)
            .add("isSuperuser", DataType.BOOLEAN)
            .build();

    return new RecordsResultSet(
        sqlSession.getMetadata().getUsers().values().stream()
            .map(
                u -> {
                  List> columns = new ArrayList<>();
                  columns.add(TextColumn.of("username", u.getName()));
                  columns.add(BooleanColumn.of("isSuperuser", u.isSuperuser()));
                  return (Record) new ColumnsRecord(columns, columnDefinitions);
                })
            .iterator(),
        columnDefinitions);
  }

  @Override
  public ResultSet visit(ShowGrantsStatement statement, SqlSession sqlSession) {
    ColumnDefinitions columnDefinitions =
        ColumnDefinitionsBuilder.builder()
            .add("name", DataType.TEXT)
            .add("type", DataType.TEXT)
            .add("privilege", DataType.TEXT)
            .build();

    Metadata metadata = sqlSession.getMetadata();

    UserMetadata user;
    if (statement.username == null) {
      user = metadata.getCurrentUser();
    } else {
      user =
          metadata
              .getUser(statement.username)
              .orElseThrow(
                  () ->
                      new IllegalArgumentException(
                          SqlError.USER_NOT_FOUND.buildMessage(statement.username)));
    }

    List records = new ArrayList<>();
    metadata
        .getNamespaces()
        .values()
        .forEach(
            n -> {
              user.getPrivileges(n.getName())
                  .forEach(
                      p -> {
                        List> columns = new ArrayList<>();
                        columns.add(TextColumn.of("name", n.getName()));
                        columns.add(TextColumn.of("type", "NAMESPACE"));
                        columns.add(TextColumn.of("privilege", p.name()));
                        records.add(new ColumnsRecord(columns, columnDefinitions));
                      });
              n.getTables()
                  .keySet()
                  .forEach(
                      t ->
                          user.getPrivileges(n.getName(), t)
                              .forEach(
                                  p -> {
                                    List> columns = new ArrayList<>();
                                    columns.add(
                                        TextColumn.of(
                                            "name",
                                            ScalarDbUtils.getFullTableName(n.getName(), t)));
                                    columns.add(TextColumn.of("type", "TABLE"));
                                    columns.add(TextColumn.of("privilege", p.name()));
                                    records.add(new ColumnsRecord(columns, columnDefinitions));
                                  }));
            });
    return new RecordsResultSet(records.iterator(), columnDefinitions);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy