text: /******************************************************************************
   * Copyright (c) 2017 Philipp Schubert.
   * All rights reserved. This program and the accompanying materials are made
   * available under the terms of LICENSE.txt.
   *
   * Contributors:
   *     Christian Stritzke, Philipp Schubert and others
   *****************************************************************************/
  
  #ifndef PHASAR_DB_HEXASTORE_H_
  #define PHASAR_DB_HEXASTORE_H_
  
  #include <array>
  #include <iosfwd>
  #include <string>
  #include <vector>
  
  #include <boost/format.hpp>
  
  #include <sqlite3.h>
  
  #include <phasar/DB/Queries.h>
  
  namespace psr {
  /**
   * @brief Holds the results of a query to the Hexastore.
   */
  struct hs_result {
    /// Used for the source node.
    std::string subject;
    /// Used for the edge.
    std::string predicate;
    /// Used for the destination node.
    std::string object;
    hs_result() = default;
    hs_result(std::string s, std::string p, std::string o)
        : subject(s), predicate(p), object(o) {}
    /// Prints an entry of the results to the command-line
    friend std::ostream &operator<<(std::ostream &os, const hs_result &hsr) {
      return os << "[ subject: " << hsr.subject
                << " | predicate: " << hsr.predicate
                << " | object: " << hsr.object << " ]";
    }
  
    friend bool operator==(const hs_result LHS, const hs_result RHS) {
      return LHS.subject == RHS.subject && LHS.predicate == RHS.predicate &&
             LHS.object == RHS.object;
    }
  };
  /**
   * A Hexastore is an efficient approach to store large graphs.
   * This approach is based on the paper "Database-Backed Program Analysis
   * for Scalable Error Propagation" by Weiss, Rubio-González and Libit.
   *
   * To store a graph into a database, we represent the graph by a set of
   * string 3-tuples by the form:
   *
   *          (source node, edge, destination node)
   *
   * A Hexastore indexes and saves graphs six-fold, according to each of
   * the permutations of source, edge and destination label. For example,
   * this allows to quickly find all edges for a given source node with one
   * look-up. In general, given one or two fixed elements of a (source, edge,
   * destination) tuple, Hexastore can quickly access the related information.
   *
   * @brief Efficient data structure for holding graphs in databases.
   */
  class Hexastore {
  private:
    sqlite3 *hs_internal_db;
    static int callback(void *NotUsed, int argc, char **argv, char **azColName);
    void doPut(std::string query, std::array<std::string, 3> edge);
  
  public:
    /**
     * If the given filename matches an already created Hexastore, no
     * new Hexastore will be created. Instead the already created Hexastore
     * will be used.
     *
     * @brief Constructs a Hexastore under the given filename.
     * @param filename Filename of the Hexastore.
     */
    Hexastore(std::string filename);
  
    /**
     * Destructor.
     */
    ~Hexastore();
  
    /**
     * Adds the given tuple as a new entry to the Hexastore. It is not
     * possible to have duplicate entries in the Hexastore and
     * duplicate put queries will be silently ignored by the Hexastore.
     *
     * @brief Creates a new entry in the Hexastore.
     * @note To mitigate certain compiler warnings, it is advised to use
     *        double braces, e.g.:
     *        hexastore.put({{"subject", "predicate", "object"}});
     * @param edge New entry in the form of a 3-tuple.
     */
    void put(std::array<std::string, 3> edge);
  
    /**
     * A query is always in the form of a 3-tuple (source, edge, destination)
     * where
     * none/one/two or all three elements of the tuple are given, while the not
     * fixed
     * elements are represented by a "?". E.g. to query all destination nodes
     * for a certain source node and edge, the following query is used:
     *
     *    ("node_19", "edge_3", "?")
     *
     * @brief Query information from the Hexastore.
     * @param edge_query Query in the form of a 3-tuple.
     * @param result_size_hint Used for possible optimization.
     * @return An object of hs_result, holding the queried information.
     */
    std::vector<hs_result> get(std::array<std::string, 3> edge_query,
                               size_t result_size_hint = 0);
  };
  
  } // namespace psr
  
  #endif
  