Example #1
0
void RepoQuery::step() {
  if (m_done) {
    throw RepoExc("RepoQuery::%s(repo=%p) error: Query done",
                  __func__, &m_stmt.repo());
  }
  int rc = sqlite3_step(m_stmt.get());
  switch (rc) {
  case SQLITE_DONE:
    m_row = false;
    m_done = true;
    break;
  case SQLITE_ROW:
    m_row = true;
    m_done = false;
    break;
  default:
    m_row = false;
    m_done = true;
    std::string errmsg = sqlite3_errmsg(m_stmt.repo().dbc());
    if (rc == SQLITE_CORRUPT) {
      auto repoId = debugComputeRepoIdFromSQL(m_stmt.repo(), m_stmt.sql());
      reportDbCorruption(m_stmt.repo(), repoId, "sqlite3_step()");
    }
    throw RepoExc("RepoQuery::%s(repo=%p) error: '%s' --> (%d) %s",
                  __func__, &m_stmt.repo(), m_stmt.sql().c_str(), rc,
                  errmsg.c_str());
  }
}
Example #2
0
void RepoQuery::getInt64(int iCol, int64_t& val) {
  if (!isInt(iCol)) {
    throw RepoExc(
      "RepoQuery::%s(repo=%p) error: Column %d is not an integer in '%s'",
      __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
  }
  val = sqlite3_column_int64(m_stmt.get(), iCol);
}
Example #3
0
void RepoQuery::getDouble(int iCol, double& val) {
  if (!isDouble(iCol)) {
    throw RepoExc(
      "RepoQuery::%s(repo=%p) error: Column %d is not a double in '%s'",
      __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
  }
  val = sqlite3_column_double(m_stmt.get(), iCol);
}
Example #4
0
void RepoQuery::getText(int iCol, const char*& text) {
  if (!isText(iCol)) {
    throw RepoExc(
      "RepoQuery::%s(repo=%p) error: Column %d is not text in '%s'",
      __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
  }
  text = (const char*)sqlite3_column_text(m_stmt.get(), iCol);
}
Example #5
0
void RepoQuery::getBlob(int iCol, const void*& blob, size_t& size) {
  if (!isBlob(iCol)) {
    throw RepoExc(
      "RepoQuery::%s(repo=%p) error: Column %d is not a blob in '%s'",
      __func__, &m_stmt.repo(), iCol, m_stmt.sql().c_str());
  }
  blob = sqlite3_column_blob(m_stmt.get(), iCol);
  size = size_t(sqlite3_column_bytes(m_stmt.get(), iCol));
}
Example #6
0
void RepoStmt::prepare(const std::string& sql) {
  finalize();
  m_sql = sql;
  int rc = sqlite3_prepare_v2(m_repo.dbc(), sql.c_str(), sql.size(), &m_stmt,
                              nullptr);
  if (rc != SQLITE_OK) {
    throw RepoExc("RepoStmt::%s(repo=%p) error: '%s' --> (%d) %s\n",
                  __func__, &m_repo, sql.c_str(), rc,
                  sqlite3_errmsg(m_repo.dbc()));
  }
}
Example #7
0
void RepoQuery::getMd5(int iCol, MD5& md5) {
  const void* blob;
  size_t size;
  getBlob(iCol, blob, size);
  if (size != 16) {
    throw RepoExc(
      "RepoQuery::%s(repo=%p) error: Column %d is the wrong size"
      " (expected 16, got %zu) in '%s'",
      __func__, &m_stmt.repo(), iCol, size, m_stmt.sql().c_str());
  }
  new (&md5) MD5(blob);
}
Example #8
0
void RepoQuery::step() {
  if (m_done) {
    throw RepoExc("RepoQuery::%s(repo=%p) error: Query done",
                  __func__, &m_stmt.repo());
  }
  int rc = sqlite3_step(m_stmt.get());
  switch (rc) {
  case SQLITE_DONE:
    m_row = false;
    m_done = true;
    break;
  case SQLITE_ROW:
    m_row = true;
    m_done = false;
    break;
  default:
    m_row = false;
    m_done = true;
    throw RepoExc("RepoQuery::%s(repo=%p) error: '%s' --> (%d) %s",
                  __func__, &m_stmt.repo(), m_stmt.sql().c_str(), rc,
                  sqlite3_errmsg(m_stmt.repo().dbc()));
  }
}
Example #9
0
void Repo::setTextPragma(int repoId, const char* name, const char* val) {
  // Pragma writes must be executed outside transactions, since they may change
  // transaction behavior.
  std::stringstream ssPragma;
  ssPragma << "PRAGMA " << dbName(repoId) << "." << name << " = " << val << ";";
  exec(ssPragma.str());
  if (debug) {
    // Verify that the pragma had the desired effect.
    std::string newval = "?";
    getTextPragma(repoId, name, newval);
    if (strcmp(newval.c_str(), val)) {
      throw RepoExc("Unexpected PRAGMA %s.%s value: %s\n",
                    dbName(repoId), name, newval.c_str());
    }
  }
}
Example #10
0
void RepoStmt::prepare(const std::string& sql) {
  finalize();
  m_sql = sql;
  int rc = sqlite3_prepare_v2(m_repo.dbc(), sql.c_str(), sql.size(), &m_stmt,
                              nullptr);
  if (rc != SQLITE_OK) {
    std::string errmsg = sqlite3_errmsg(m_repo.dbc());
    if (rc == SQLITE_CORRUPT) {
      auto repoId = debugComputeRepoIdFromSQL(repo(), sql);
      reportDbCorruption(m_repo, repoId, "sqlite3_prepare_v2()");
    }
    throw RepoExc("RepoStmt::%s(repo=%p) error: '%s' --> (%d) %s\n",
                  __func__, &m_repo, sql.c_str(), rc,
                  errmsg.c_str());
  }
}
Example #11
0
void Repo::loadGlobalData(bool allowFailure /* = false */) {
  m_lsrp.load();

  if (!RuntimeOption::RepoAuthoritative) return;

  std::vector<std::string> failures;

  /*
   * This should probably just go to the Local repo always, except
   * that our unit test suite is currently running RepoAuthoritative
   * tests with the compiled repo as the Central repo.
   */
  for (int repoId = RepoIdCount - 1; repoId >= 0; --repoId) {
    if (repoName(repoId).empty()) {
      // The repo wasn't loadable
      continue;
    }
    try {
      RepoStmt stmt(*this);
      const auto& tbl = table(repoId, "GlobalData");
      stmt.prepare(
        folly::format(
          "SELECT count(*), data from {};", tbl
        ).str()
      );
      RepoTxn txn(*this);
      RepoTxnQuery query(txn, stmt);
      query.step();
      if (!query.row()) {
        throw RepoExc("Can't find table %s", tbl.c_str());
      };
      int val;
      query.getInt(0, val);
      if (val == 0) {
        throw RepoExc("No rows in %s. Did you forget to compile that file with "
                      "this HHVM version?", tbl.c_str());
      };
      BlobDecoder decoder = query.getBlob(1);
      decoder(s_globalData);

      txn.commit();
    } catch (RepoExc& e) {
      failures.push_back(repoName(repoId) + ": "  + e.msg());
      continue;
    }

    // TODO: this should probably read out the other elements of the global data
    // which control Option or RuntimeOption values -- the others are read out
    // in an inconsistent and ad-hoc manner. But I don't understand their uses
    // and interactions well enough to feel comfortable fixing now.
    RuntimeOption::PHP7_IntSemantics = s_globalData.PHP7_IntSemantics;
    RuntimeOption::PHP7_ScalarTypes  = s_globalData.PHP7_ScalarTypes;
    RuntimeOption::AutoprimeGenerators = s_globalData.AutoprimeGenerators;

    return;
  }

  if (allowFailure) return;

  if (failures.empty()) {
    std::fprintf(stderr, "No repo was loadable. Check all the possible repo "
                 "locations (Repo.Central.Path, HHVM_REPO_CENTRAL_PATH, and "
                 "$HOME/.hhvm.hhbc) to make sure one of them is a valid "
                 "sqlite3 HHVM repo built with this exact HHVM version.\n");
  } else {
    // We should always have a global data section in RepoAuthoritative
    // mode, or the repo is messed up.
    std::fprintf(stderr, "Failed to load Repo::GlobalData:\n");
    for (auto& f : failures) {
      std::fprintf(stderr, "  %s\n", f.c_str());
    }
  }

  assert(Process::IsInMainThread());
  exit(1);
}
Example #12
0
void Repo::loadGlobalData(bool allowFailure /* = false */,
                          bool readArrayTable /* = true */) {
  if (readArrayTable) m_lsrp.load();

  if (!RuntimeOption::RepoAuthoritative) return;

  std::vector<std::string> failures;

  /*
   * This should probably just go to the Local repo always, except
   * that our unit test suite is currently running RepoAuthoritative
   * tests with the compiled repo as the Central repo.
   */
  for (int repoId = RepoIdCount - 1; repoId >= 0; --repoId) {
    if (repoName(repoId).empty()) {
      // The repo wasn't loadable
      continue;
    }
    try {
      RepoStmt stmt(*this);
      const auto& tbl = table(repoId, "GlobalData");
      stmt.prepare(
        folly::format(
          "SELECT count(*), data from {};", tbl
        ).str()
      );
      RepoTxn txn(*this);
      RepoTxnQuery query(txn, stmt);
      query.step();
      if (!query.row()) {
        throw RepoExc("Can't find table %s", tbl.c_str());
      };
      int val;
      query.getInt(0, val);
      if (val == 0) {
        throw RepoExc("No rows in %s. Did you forget to compile that file with "
                      "this HHVM version?", tbl.c_str());
      }
      BlobDecoder decoder = query.getBlob(1);
      decoder(s_globalData);
      if (readArrayTable) {
        auto& arrayTypeTable = globalArrayTypeTable();
        decoder(arrayTypeTable);
        decoder(s_globalData.APCProfile);
        decoder(s_globalData.ConstantFunctions);
        decoder.assertDone();
      }
      txn.commit();
    } catch (RepoExc& e) {
      failures.push_back(repoName(repoId) + ": "  + e.msg());
      continue;
    }

    // TODO: this should probably read out the other elements of the global data
    // which control Option or RuntimeOption values -- the others are read out
    // in an inconsistent and ad-hoc manner. But I don't understand their uses
    // and interactions well enough to feel comfortable fixing now.
    RuntimeOption::EvalPromoteEmptyObject    = s_globalData.PromoteEmptyObject;
    RuntimeOption::EnableIntrinsicsExtension =
      s_globalData.EnableIntrinsicsExtension;
    HHBBC::options.ElideAutoloadInvokes     = s_globalData.ElideAutoloadInvokes;
    RuntimeOption::AutoprimeGenerators      = s_globalData.AutoprimeGenerators;
    RuntimeOption::EnableHipHopSyntax       = s_globalData.EnableHipHopSyntax;
    RuntimeOption::EvalHardTypeHints        = s_globalData.HardTypeHints;
    RuntimeOption::EvalUseHHBBC             = s_globalData.UsedHHBBC;
    RuntimeOption::PHP7_Builtins            = s_globalData.PHP7_Builtins;
    RuntimeOption::PHP7_IntSemantics        = s_globalData.PHP7_IntSemantics;
    RuntimeOption::PHP7_NoHexNumerics       = s_globalData.PHP7_NoHexNumerics;
    RuntimeOption::PHP7_ScalarTypes         = s_globalData.PHP7_ScalarTypes;
    RuntimeOption::PHP7_Substr              = s_globalData.PHP7_Substr;
    RuntimeOption::EvalReffinessInvariance  = s_globalData.ReffinessInvariance;
    RuntimeOption::EvalHackArrDVArrs        = s_globalData.HackArrDVArrs;
    RuntimeOption::DisallowDynamicVarEnvFuncs =
      s_globalData.DisallowDynamicVarEnvFuncs;

    if (s_globalData.HardReturnTypeHints) {
      RuntimeOption::EvalCheckReturnTypeHints = 3;
    }
    if (s_globalData.ThisTypeHintLevel == 3) {
      RuntimeOption::EvalThisTypeHintLevel = s_globalData.ThisTypeHintLevel;
    }
    RuntimeOption::ConstantFunctions.clear();
    for (auto const& elm : s_globalData.ConstantFunctions) {
      RuntimeOption::ConstantFunctions.insert(elm);
    }

    return;
  }

  if (allowFailure) return;

  if (failures.empty()) {
    std::fprintf(stderr, "No repo was loadable. Check all the possible repo "
                 "locations (Repo.Central.Path, HHVM_REPO_CENTRAL_PATH, and "
                 "$HOME/.hhvm.hhbc) to make sure one of them is a valid "
                 "sqlite3 HHVM repo built with this exact HHVM version.\n");
  } else {
    // We should always have a global data section in RepoAuthoritative
    // mode, or the repo is messed up.
    std::fprintf(stderr, "Failed to load Repo::GlobalData:\n");
    for (auto& f : failures) {
      std::fprintf(stderr, "  %s\n", f.c_str());
    }
  }

  assertx(Process::IsInMainThread());
  exit(1);
}