Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Add the framework for the pg_statistic table. #1416

Merged
merged 19 commits into from
Jan 24, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion src/catalog/database_catalog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "catalog/postgres/pg_index.h"
#include "catalog/postgres/pg_namespace.h"
#include "catalog/postgres/pg_proc.h"
#include "catalog/postgres/pg_statistic.h"
#include "catalog/postgres/pg_type.h"
#include "catalog/schema.h"
#include "common/error/error_code.h"
Expand All @@ -38,7 +39,8 @@ DatabaseCatalog::DatabaseCatalog(const db_oid_t oid,
pg_type_(db_oid_),
pg_constraint_(db_oid_),
pg_language_(db_oid_),
pg_proc_(db_oid_) {}
pg_proc_(db_oid_),
pg_stat_(db_oid_) {}

void DatabaseCatalog::TearDown(const common::ManagedPointer<transaction::TransactionContext> txn) {
auto teardown_pg_core = pg_core_.GetTearDownFn(txn, common::ManagedPointer(this));
Expand Down Expand Up @@ -112,6 +114,11 @@ table_oid_t DatabaseCatalog::CreateTable(const common::ManagedPointer<transactio
bool DatabaseCatalog::DeleteTable(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table) {
if (!TryLock(txn)) return false;
// Delete associated entries in pg_statistic
{
auto result = pg_stat_.DeleteColumnStatistics<Schema::Column>(txn, table);
if (!result) return false;
}
return pg_core_.DeleteTable(txn, common::ManagedPointer(this), table);
}

Expand Down Expand Up @@ -325,6 +332,11 @@ void DatabaseCatalog::BootstrapIndex(const common::ManagedPointer<transaction::T
bool DatabaseCatalog::CreateTableEntry(const common::ManagedPointer<transaction::TransactionContext> txn,
const table_oid_t table_oid, const namespace_oid_t ns_oid,
const std::string &name, const Schema &schema) {
col_oid_t curr_col_oid(1);
for (auto &col : schema.GetColumns()) {
col_oid_t col_oid(curr_col_oid++);
pg_stat_.CreateColumnStatistic(txn, table_oid, col_oid, col);
}
return pg_core_.CreateTableEntry(txn, table_oid, ns_oid, name, schema);
}

Expand Down
46 changes: 46 additions & 0 deletions src/catalog/postgres/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "catalog/postgres/pg_language.h"
#include "catalog/postgres/pg_namespace.h"
#include "catalog/postgres/pg_proc.h"
#include "catalog/postgres/pg_statistic.h"
#include "catalog/postgres/pg_type.h"
#include "catalog/schema.h"
#include "parser/expression/abstract_expression.h"
Expand Down Expand Up @@ -82,6 +83,7 @@ DatabaseCatalog *Builder::CreateDatabaseCatalog(
dbc->pg_constraint_.constraints_ = new storage::SqlTable(block_store, Builder::GetConstraintTableSchema());
dbc->pg_language_.languages_ = new storage::SqlTable(block_store, Builder::GetLanguageTableSchema());
dbc->pg_proc_.procs_ = new storage::SqlTable(block_store, Builder::GetProcTableSchema());
dbc->pg_stat_.statistics_ = new storage::SqlTable(block_store, Builder::GetStatisticTableSchema());

// Indexes on pg_namespace
dbc->pg_core_.namespaces_oid_index_ =
Expand Down Expand Up @@ -143,6 +145,10 @@ DatabaseCatalog *Builder::CreateDatabaseCatalog(
dbc->pg_proc_.procs_name_index_ =
Builder::BuildLookupIndex(Builder::GetProcNameIndexSchema(oid), PgProc::PRO_NAME_INDEX_OID);

// Indexes on pg_statistic
dbc->pg_stat_.statistics_oid_index_ =
Builder::BuildUniqueIndex(Builder::GetStatisticOidIndexSchema(oid), PgStatistic::STATISTIC_OID_INDEX_OID);

dbc->next_oid_.store(START_OID);

return dbc;
Expand Down Expand Up @@ -670,6 +676,27 @@ IndexSchema Builder::GetLanguageNameIndexSchema(db_oid_t db) {
return schema;
}

Schema Builder::GetStatisticTableSchema() {
std::vector<Schema::Column> columns;

columns.emplace_back("starelid", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STARELID_COL_OID.oid_);

columns.emplace_back("staattnum", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STAATTNUM_COL_OID.oid_);

columns.emplace_back("stanullrows", type::TypeId::INTEGER, false,
parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STANULLROWS_COL_OID.oid_);

columns.emplace_back("numrows", type::TypeId::INTEGER, false, parser::ConstantValueExpression(type::TypeId::INTEGER));
columns.back().SetOid(PgStatistic::STA_NUMROWS_COL_OID.oid_);

return Schema(columns);
}

Schema Builder::GetProcTableSchema() {
std::vector<Schema::Column> columns;

Expand Down Expand Up @@ -795,6 +822,25 @@ IndexSchema Builder::GetProcNameIndexSchema(db_oid_t db) {
return schema;
}

IndexSchema Builder::GetStatisticOidIndexSchema(db_oid_t db) {
std::vector<IndexSchema::Column> columns;

columns.emplace_back("starelid", type::TypeId::INTEGER, false,
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID,
PgStatistic::STARELID_COL_OID.oid_));
columns.back().SetOid(indexkeycol_oid_t(1));

columns.emplace_back("staattnum", type::TypeId::INTEGER, false,
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID,
PgStatistic::STAATTNUM_COL_OID.oid_));
columns.back().SetOid(indexkeycol_oid_t(2));

// Primary
IndexSchema schema(columns, storage::index::IndexType::BWTREE, true, true, false, true);

return schema;
}

storage::index::Index *Builder::BuildUniqueIndex(const IndexSchema &key_schema, index_oid_t oid) {
NOISEPAGE_ASSERT(key_schema.Unique(), "KeySchema must represent a unique index.");
storage::index::IndexBuilder index_builder;
Expand Down
3 changes: 2 additions & 1 deletion src/catalog/postgres/pg_core_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,8 @@ bool PgCoreImpl::CreateTableEntry(const common::ManagedPointer<transaction::Tran
{
col_oid_t curr_col_oid(1);
for (auto &col : schema.GetColumns()) {
auto success = CreateColumn(txn, table_oid, curr_col_oid++, col);
col_oid_t col_oid(curr_col_oid++);
auto success = CreateColumn(txn, table_oid, col_oid, col);
if (!success) return false;
}
}
Expand Down
140 changes: 140 additions & 0 deletions src/catalog/postgres/pg_statistic_impl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#include "catalog/postgres/pg_statistic_impl.h"

#include "catalog/database_catalog.h"
#include "catalog/index_schema.h"
#include "catalog/schema.h"
#include "catalog/postgres/builder.h"
#include "catalog/postgres/pg_namespace.h"
#include "storage/index/index.h"
#include "storage/sql_table.h"

namespace noisepage::catalog::postgres {

void PgStatisticImpl::Bootstrap(common::ManagedPointer<transaction::TransactionContext> txn,
common::ManagedPointer<DatabaseCatalog> dbc) {
// pg_statistic and associated indexes.
dbc->BootstrapTable(txn, PgStatistic::STATISTIC_TABLE_OID, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID,
"pg_statistic", Builder::GetStatisticTableSchema(), statistics_);
dbc->BootstrapIndex(txn, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID, PgStatistic::STATISTIC_TABLE_OID,
PgStatistic::STATISTIC_OID_INDEX_OID, "pg_statistic_index",
Builder::GetStatisticOidIndexSchema(db_oid_), statistics_oid_index_);
}

void PgStatisticImpl::BootstrapPRIs() {
const std::vector<col_oid_t> pg_statistic_all_oids{PgStatistic::PG_STATISTIC_ALL_COL_OIDS.cbegin(),
PgStatistic::PG_STATISTIC_ALL_COL_OIDS.end()};
pg_statistic_all_cols_pri_ = statistics_->InitializerForProjectedRow(pg_statistic_all_oids);
pg_statistic_all_cols_prm_ = statistics_->ProjectionMapForOids(pg_statistic_all_oids);

// Used to select rows to delete in DeleteColumnStatistics
const std::vector<col_oid_t> delete_statistics_oids{PgStatistic::STAATTNUM_COL_OID.oid_};
delete_statistics_pri_ = statistics_->InitializerForProjectedRow(delete_statistics_oids);
delete_statistics_prm_ = statistics_->ProjectionMapForOids(delete_statistics_oids);
}

template <typename Column, typename ClassOid, typename ColOid>
void PgStatisticImpl::CreateColumnStatistic(const common::ManagedPointer<transaction::TransactionContext> txn,
const ClassOid class_oid, const ColOid col_oid, const Column &col) {
// Step 1: Insert into the table
auto *const redo = txn->StageWrite(db_oid_, PgStatistic::STATISTIC_TABLE_OID, pg_statistic_all_cols_pri_);
auto delta = common::ManagedPointer(redo->Delta());
auto &pm = pg_statistic_all_cols_prm_;

// Insert into pg_statistic.
{
PgStatistic::STARELID_COL_OID.Set(delta, pm, class_oid);
PgStatistic::STAATTNUM_COL_OID.Set(delta, pm, col_oid);
PgStatistic::STANULLROWS_COL_OID.Set(delta, pm, 0);
PgStatistic::STA_NUMROWS_COL_OID.Set(delta, pm, 0);
}

// Finally, insert into the table to get the tuple slot
const auto tupleslot = statistics_->Insert(txn, redo);

// Step 2: Insert into oid index
const auto oid_pri = statistics_oid_index_->GetProjectedRowInitializer();
auto oid_prm = statistics_oid_index_->GetKeyOidToOffsetMap();
// Create a buffer large enough for all columns
auto const buffer = std::unique_ptr<byte[]>(common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize()));
auto *pr = oid_pri.InitializeRow(buffer.get());
// Write the attributes in the ProjectedRow. These hardcoded indexkeycol_oids come from
// Builder::GetStatisticOidIndexSchema()
*(reinterpret_cast<ClassOid *>(pr->AccessForceNotNull(oid_prm[indexkeycol_oid_t(1)]))) = class_oid;
*(reinterpret_cast<ColOid *>(pr->AccessForceNotNull(oid_prm[indexkeycol_oid_t(2)]))) = col_oid;

bool UNUSED_ATTRIBUTE result = statistics_oid_index_->InsertUnique(txn, *pr, tupleslot);
NOISEPAGE_ASSERT(result, "Assigned OIDs failed to be unique.");
}

template <typename Column, typename ClassOid>
bool PgStatisticImpl::DeleteColumnStatistics(const common::ManagedPointer<transaction::TransactionContext> txn,
const ClassOid class_oid) {
const auto &oid_pri = statistics_oid_index_->GetProjectedRowInitializer();
const auto &oid_prm = statistics_oid_index_->GetKeyOidToOffsetMap();

// Step 1: Read Index
std::vector<storage::TupleSlot> index_results;
{
// Buffer is large enough to hold all prs
const std::unique_ptr<byte[]> buffer_lo(common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize()));
const std::unique_ptr<byte[]> buffer_hi(common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize()));

// Scan the class index
auto *pr_lo = oid_pri.InitializeRow(buffer_lo.get());
auto *pr_hi = oid_pri.InitializeRow(buffer_hi.get());

// Write the attributes in the ProjectedRow
// Low key (class, INVALID_COLUMN_OID) [using uint32_t to avoid adding ColOid to template]
*(reinterpret_cast<ClassOid *>(pr_lo->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(1))))) = class_oid;
*(reinterpret_cast<uint32_t *>(pr_lo->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(2))))) = 0;

auto next_oid = ClassOid(class_oid + 1);
// High key (class + 1, INVALID_COLUMN_OID) [using uint32_t to avoid adding ColOid to template]
*(reinterpret_cast<ClassOid *>(pr_hi->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(1))))) = next_oid;
*(reinterpret_cast<uint32_t *>(pr_hi->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(2))))) = 0;

statistics_oid_index_->ScanAscending(*txn, storage::index::ScanType::Closed, 2, pr_lo, pr_hi, 0, &index_results);
}

NOISEPAGE_ASSERT(!index_results.empty(),
"Incorrect number of results from index scan. empty() implies that function was called with an oid "
"that doesn't exist in the Catalog, but binding somehow succeeded. That doesn't make sense.");

// TODO(Matt): do we have any way to assert that we got the number of attributes we expect? From another attribute in
// another catalog table maybe?

// Step 2: Scan the table to get the columns
const std::unique_ptr<byte[]> buffer(
common::AllocationUtil::AllocateAligned(delete_statistics_pri_.ProjectedRowSize()));
const std::unique_ptr<byte[]> key_buffer(common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize()));

auto *pr = delete_statistics_pri_.InitializeRow(buffer.get());
for (const auto &slot : index_results) {
// 1. Extract attributes from the tuple for the index deletions
auto UNUSED_ATTRIBUTE result = statistics_->Select(txn, slot, pr);
NOISEPAGE_ASSERT(result, "Index scan did a visibility check, so Select shouldn't fail at this point.");
const auto *const col_oid = reinterpret_cast<const uint32_t *const>(
pr->AccessWithNullCheck(delete_statistics_prm_.at(PgStatistic::STAATTNUM_COL_OID.oid_)));
NOISEPAGE_ASSERT(col_oid != nullptr, "OID shouldn't be NULL.");

// 2. Delete from the table
txn->StageDelete(db_oid_, PgStatistic::STATISTIC_TABLE_OID, slot);
result = statistics_->Delete(txn, slot);
if (!result) {
// Failed to delete one of the columns, return false to indicate failure
return false;
}

// 3. Delete from oid index
auto *key_pr = oid_pri.InitializeRow(key_buffer.get());
// Write the attributes in the ProjectedRow. These hardcoded indexkeycol_oids come from
// Builder::GetStatisticOidIndexSchema()
*(reinterpret_cast<ClassOid *>(key_pr->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(1))))) = class_oid;
*(reinterpret_cast<uint32_t *>(key_pr->AccessForceNotNull(oid_prm.at(indexkeycol_oid_t(2))))) = *col_oid;
statistics_oid_index_->Delete(txn, *key_pr, slot);
}

return true;
}

} // namespace noisepage::catalog::postgres
3 changes: 3 additions & 0 deletions src/include/catalog/database_catalog.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "catalog/postgres/pg_core_impl.h"
#include "catalog/postgres/pg_language_impl.h"
#include "catalog/postgres/pg_proc_impl.h"
#include "catalog/postgres/pg_statistic_impl.h"
#include "catalog/postgres/pg_type_impl.h"
#include "common/managed_pointer.h"

Expand Down Expand Up @@ -192,6 +193,7 @@ class DatabaseCatalog {
friend class postgres::PgLanguageImpl;
friend class postgres::PgProcImpl;
friend class postgres::PgTypeImpl;
friend class postgres::PgStatisticImpl;
///@}
friend class Catalog; ///< Accesses write_lock_ (creating accessor) and TearDown (cleanup).
friend class postgres::Builder; ///< Initializes DatabaseCatalog's tables.
Expand All @@ -209,6 +211,7 @@ class DatabaseCatalog {
postgres::PgConstraintImpl pg_constraint_; ///< Constraints: pg_constraint.
postgres::PgLanguageImpl pg_language_; ///< Languages: pg_language.
postgres::PgProcImpl pg_proc_; ///< Procedures: pg_proc.
postgres::PgStatisticImpl pg_stat_; ///< Statistics: pg_statistic.

/** @brief Create a new DatabaseCatalog. Does not create any tables until Bootstrap is called. */
DatabaseCatalog(db_oid_t oid, common::ManagedPointer<storage::GarbageCollector> garbage_collector);
Expand Down
11 changes: 11 additions & 0 deletions src/include/catalog/postgres/builder.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ class Builder {
*/
static Schema GetProcTableSchema();

/**
* @return schema object for pg_statistic table
*/
static Schema GetStatisticTableSchema();

/**
* @param db oid in which the indexed table exists
* @return schema object for the oid index on pg_namespace
Expand Down Expand Up @@ -225,6 +230,12 @@ class Builder {
*/
static IndexSchema GetProcNameIndexSchema(db_oid_t db);

/**
* @param db oid in which the indexed table exists
* @return schema object for the table/oid index on pg_statistic
*/
static IndexSchema GetStatisticOidIndexSchema(db_oid_t db);

/**
* Instantiate a new unique index with the given schema and oid
* @param key_schema for the index
Expand Down
3 changes: 3 additions & 0 deletions src/include/catalog/postgres/pg_core_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ class PgCoreImpl {
void BootstrapPRIsPgClass();
void BootstrapPRIsPgIndex();
void BootstrapPRIsPgAttribute();
void BootstrapPRIsPgStatistic();
void BootstrapPgNamespace(common::ManagedPointer<transaction::TransactionContext> txn,
common::ManagedPointer<DatabaseCatalog> dbc);
void BootstrapPgClass(common::ManagedPointer<transaction::TransactionContext> txn,
Expand All @@ -312,6 +313,8 @@ class PgCoreImpl {
common::ManagedPointer<DatabaseCatalog> dbc);
void BootstrapPgAttribute(common::ManagedPointer<transaction::TransactionContext> txn,
common::ManagedPointer<DatabaseCatalog> dbc);
void BootstrapPgStatistic(common::ManagedPointer<transaction::TransactionContext> txn,
common::ManagedPointer<DatabaseCatalog> dbc);
///@}

/**
Expand Down
36 changes: 36 additions & 0 deletions src/include/catalog/postgres/pg_statistic.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#pragma once

#include <array>

#include "catalog/catalog_column_def.h"
#include "catalog/catalog_defs.h"

namespace noisepage::storage {
class RecoveryManager;
} // namespace noisepage::storage

namespace noisepage::catalog::postgres {
class Builder;
class PgStatisticImpl;

class PgStatistic {
public:
static constexpr table_oid_t STATISTIC_TABLE_OID = table_oid_t(91);
static constexpr index_oid_t STATISTIC_OID_INDEX_OID = index_oid_t(92);

private:
friend class Builder;
friend class PgStatisticImpl;

static constexpr CatalogColumnDef<table_oid_t, uint32_t> STARELID_COL_OID{col_oid_t{1}};
static constexpr CatalogColumnDef<col_oid_t , uint32_t> STAATTNUM_COL_OID{col_oid_t{2}};
static constexpr CatalogColumnDef<uint32_t, uint32_t> STANULLROWS_COL_OID{col_oid_t{3}};
static constexpr CatalogColumnDef<uint32_t, uint32_t> STA_NUMROWS_COL_OID{col_oid_t{4}};

static constexpr uint8_t NUM_PG_STATISTIC_COLS = 4;

static constexpr std::array<col_oid_t, NUM_PG_STATISTIC_COLS> PG_STATISTIC_ALL_COL_OIDS = {
STARELID_COL_OID.oid_, STAATTNUM_COL_OID.oid_, STANULLROWS_COL_OID.oid_, STA_NUMROWS_COL_OID.oid_};
};

} // namespace terrier::catalog::postgres
Loading