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

com.scalar.db.storage.jdbc.query.SimpleSelectQuery Maven / Gradle / Ivy

Go to download

A universal transaction manager that achieves database-agnostic transactions and distributed transactions that span multiple databases

There is a newer version: 3.14.0
Show newest version
package com.scalar.db.storage.jdbc.query;

import com.scalar.db.api.ConditionalExpression;
import com.scalar.db.api.Scan;
import com.scalar.db.api.Scan.Conjunction;
import com.scalar.db.api.TableMetadata;
import com.scalar.db.io.Column;
import com.scalar.db.io.Key;
import com.scalar.db.storage.jdbc.RdbEngineStrategy;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.concurrent.ThreadSafe;

@ThreadSafe
public class SimpleSelectQuery implements SelectQuery {

  private final List projections;
  private final RdbEngineStrategy rdbEngine;
  private final String schema;
  private final String table;
  private final TableMetadata tableMetadata;
  private final Optional partitionKey;
  private final Optional clusteringKey;
  private final Optional commonClusteringKey;
  private final Optional> startColumn;
  private final boolean startInclusive;
  private final Optional> endColumn;
  private final boolean endInclusive;
  private final List orderings;
  private final boolean isRangeQuery;
  private final Optional indexedColumn;
  private final boolean isConditionalQuery;
  private final boolean isRelationalQuery;
  private final Set conjunctions;

  SimpleSelectQuery(Builder builder) {
    projections = builder.projections;
    rdbEngine = builder.rdbEngine;
    schema = builder.schema;
    table = builder.table;
    tableMetadata = builder.tableMetadata;
    partitionKey = builder.partitionKey;
    clusteringKey = builder.clusteringKey;
    commonClusteringKey = builder.commonClusteringKey;
    startColumn = builder.startColumn;
    startInclusive = builder.startInclusive;
    endColumn = builder.endColumn;
    endInclusive = builder.endInclusive;
    orderings = builder.orderings;
    isRangeQuery = builder.isRangeQuery;
    indexedColumn = builder.indexedColumn;
    isConditionalQuery = builder.isConditionalQuery;
    isRelationalQuery = builder.isRelationalQuery;
    conjunctions = builder.conjunctions;
  }

  @Override
  public String sql() {
    StringBuilder builder =
        new StringBuilder("SELECT ")
            .append(projectionSqlString())
            .append(" FROM ")
            .append(rdbEngine.encloseFullTableName(schema, table));
    if (isRelationalQuery) {
      // for relational abstraction
      builder.append(relationalConditionSqlString());
      builder.append(relationalOrderBySqlString());
    } else {
      // for multi-dimensional map abstraction
      if (isConditionalQuery) {
        builder.append(" WHERE ");
        builder.append(conditionSqlString());
      }
      builder.append(orderBySqlString());
    }

    return builder.toString();
  }

  private String projectionSqlString() {
    if (projections.isEmpty()) {
      return "*";
    }
    return projections.stream().map(rdbEngine::enclose).collect(Collectors.joining(","));
  }

  private String conditionSqlString() {
    List conditions = new ArrayList<>();
    partitionKey.ifPresent(
        k -> k.forEach(v -> conditions.add(rdbEngine.enclose(v.getName()) + "=?")));
    clusteringKey.ifPresent(
        k -> k.forEach(v -> conditions.add(rdbEngine.enclose(v.getName()) + "=?")));
    commonClusteringKey.ifPresent(
        k -> k.forEach(v -> conditions.add(rdbEngine.enclose(v.getName()) + "=?")));
    startColumn.ifPresent(
        c -> conditions.add(rdbEngine.enclose(c.getName()) + (startInclusive ? ">=?" : ">?")));
    endColumn.ifPresent(
        c -> conditions.add(rdbEngine.enclose(c.getName()) + (endInclusive ? "<=?" : " conjunctionList =
        conjunctions.stream()
            .map(
                conjunction ->
                    conjunction.getConditions().stream()
                        .map(
                            condition ->
                                rdbEngine.enclose(condition.getColumn().getName())
                                    + convert(condition.getOperator()))
                        .collect(Collectors.joining(" AND ")))
            .collect(Collectors.toList());

    return " WHERE " + String.join(" OR ", conjunctionList);
  }

  private String convert(ConditionalExpression.Operator operator) {
    switch (operator) {
      case EQ:
        return "=?";
      case NE:
        return "!=?";
      case GT:
        return ">?";
      case GTE:
        return ">=?";
      case LT:
        return " orderingList = new ArrayList<>(orderings);

    Boolean reverse = null;
    int i = 0;
    for (String clusteringKeyName : tableMetadata.getClusteringKeyNames()) {
      if (i < orderings.size()) {
        Scan.Ordering ordering = orderings.get(i++);
        if (reverse == null) {
          reverse =
              ordering.getOrder() != tableMetadata.getClusteringOrder(ordering.getColumnName());
        }
      } else {
        Scan.Ordering.Order order = tableMetadata.getClusteringOrder(clusteringKeyName);

        if (reverse != null && reverse) {
          if (order == Scan.Ordering.Order.ASC) {
            order = Scan.Ordering.Order.DESC;
          } else {
            order = Scan.Ordering.Order.ASC;
          }
        }
        orderingList.add(new Scan.Ordering(clusteringKeyName, order));
      }
    }

    return " ORDER BY "
        + orderingList.stream()
            .map(o -> rdbEngine.enclose(o.getColumnName()) + " " + o.getOrder())
            .collect(Collectors.joining(","));
  }

  private String relationalOrderBySqlString() {
    if (orderings.isEmpty()) {
      return "";
    }

    return " ORDER BY "
        + orderings.stream()
            .map(o -> rdbEngine.enclose(o.getColumnName()) + " " + o.getOrder())
            .collect(Collectors.joining(","));
  }

  @Override
  public void bind(PreparedStatement preparedStatement) throws SQLException {
    PreparedStatementBinder binder =
        new PreparedStatementBinder(preparedStatement, tableMetadata, rdbEngine);
    if (partitionKey.isPresent()) {
      for (Column column : partitionKey.get().getColumns()) {
        column.accept(binder);
        binder.throwSQLExceptionIfOccurred();
      }
    }

    if (clusteringKey.isPresent()) {
      for (Column column : clusteringKey.get().getColumns()) {
        column.accept(binder);
        binder.throwSQLExceptionIfOccurred();
      }
    }

    if (commonClusteringKey.isPresent()) {
      for (Column column : commonClusteringKey.get().getColumns()) {
        column.accept(binder);
        binder.throwSQLExceptionIfOccurred();
      }
    }

    if (startColumn.isPresent()) {
      startColumn.get().accept(binder);
      binder.throwSQLExceptionIfOccurred();
    }

    if (endColumn.isPresent()) {
      endColumn.get().accept(binder);
      binder.throwSQLExceptionIfOccurred();
    }

    for (Conjunction conjunction : conjunctions) {
      for (ConditionalExpression condition : conjunction.getConditions()) {
        if (!condition.getColumn().hasNullValue()) {
          condition.getColumn().accept(binder);
          binder.throwSQLExceptionIfOccurred();
        }
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy