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

Commit d60c55a

Browse files
preetansharvindsaiklmwnshn
authored
Add the framework for the pg_statistic table. (#1416)
Co-authored-by: Arvind Sai Krishnan <[email protected]> Co-authored-by: Wan Shen Lim <[email protected]>
1 parent 3ebdd86 commit d60c55a

File tree

9 files changed

+368
-8
lines changed

9 files changed

+368
-8
lines changed

src/catalog/database_catalog.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "catalog/postgres/pg_index.h"
1515
#include "catalog/postgres/pg_namespace.h"
1616
#include "catalog/postgres/pg_proc.h"
17+
#include "catalog/postgres/pg_statistic.h"
1718
#include "catalog/postgres/pg_type.h"
1819
#include "catalog/schema.h"
1920
#include "common/error/error_code.h"
@@ -38,7 +39,8 @@ DatabaseCatalog::DatabaseCatalog(const db_oid_t oid,
3839
pg_type_(db_oid_),
3940
pg_constraint_(db_oid_),
4041
pg_language_(db_oid_),
41-
pg_proc_(db_oid_) {}
42+
pg_proc_(db_oid_),
43+
pg_stat_(db_oid_) {}
4244

4345
void DatabaseCatalog::TearDown(const common::ManagedPointer<transaction::TransactionContext> txn) {
4446
auto teardown_pg_core = pg_core_.GetTearDownFn(txn, common::ManagedPointer(this));
@@ -66,6 +68,7 @@ void DatabaseCatalog::BootstrapPRIs() {
6668
pg_constraint_.BootstrapPRIs();
6769
pg_language_.BootstrapPRIs();
6870
pg_proc_.BootstrapPRIs();
71+
pg_stat_.BootstrapPRIs();
6972
}
7073

7174
void DatabaseCatalog::Bootstrap(const common::ManagedPointer<transaction::TransactionContext> txn) {
@@ -82,6 +85,7 @@ void DatabaseCatalog::Bootstrap(const common::ManagedPointer<transaction::Transa
8285
pg_constraint_.Bootstrap(txn, common::ManagedPointer(this));
8386
pg_language_.Bootstrap(txn, common::ManagedPointer(this));
8487
pg_proc_.Bootstrap(txn, common::ManagedPointer(this));
88+
pg_stat_.Bootstrap(txn, common::ManagedPointer(this));
8589
}
8690

8791
namespace_oid_t DatabaseCatalog::CreateNamespace(const common::ManagedPointer<transaction::TransactionContext> txn,
@@ -112,6 +116,11 @@ table_oid_t DatabaseCatalog::CreateTable(const common::ManagedPointer<transactio
112116
bool DatabaseCatalog::DeleteTable(const common::ManagedPointer<transaction::TransactionContext> txn,
113117
const table_oid_t table) {
114118
if (!TryLock(txn)) return false;
119+
// Delete associated entries in pg_statistic.
120+
{
121+
auto result = pg_stat_.DeleteColumnStatistics(txn, table);
122+
if (!result) return false;
123+
}
115124
return pg_core_.DeleteTable(txn, common::ManagedPointer(this), table);
116125
}
117126

@@ -325,6 +334,13 @@ void DatabaseCatalog::BootstrapIndex(const common::ManagedPointer<transaction::T
325334
bool DatabaseCatalog::CreateTableEntry(const common::ManagedPointer<transaction::TransactionContext> txn,
326335
const table_oid_t table_oid, const namespace_oid_t ns_oid,
327336
const std::string &name, const Schema &schema) {
337+
// Create associated entries in pg_statistic.
338+
{
339+
col_oid_t col_oid(1);
340+
for (auto &col : schema.GetColumns()) {
341+
pg_stat_.CreateColumnStatistic(txn, table_oid, col_oid++, col);
342+
}
343+
}
328344
return pg_core_.CreateTableEntry(txn, table_oid, ns_oid, name, schema);
329345
}
330346

src/catalog/postgres/builder.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "catalog/postgres/pg_language.h"
1414
#include "catalog/postgres/pg_namespace.h"
1515
#include "catalog/postgres/pg_proc.h"
16+
#include "catalog/postgres/pg_statistic.h"
1617
#include "catalog/postgres/pg_type.h"
1718
#include "catalog/schema.h"
1819
#include "parser/expression/abstract_expression.h"
@@ -82,6 +83,7 @@ DatabaseCatalog *Builder::CreateDatabaseCatalog(
8283
dbc->pg_constraint_.constraints_ = new storage::SqlTable(block_store, Builder::GetConstraintTableSchema());
8384
dbc->pg_language_.languages_ = new storage::SqlTable(block_store, Builder::GetLanguageTableSchema());
8485
dbc->pg_proc_.procs_ = new storage::SqlTable(block_store, Builder::GetProcTableSchema());
86+
dbc->pg_stat_.statistics_ = new storage::SqlTable(block_store, Builder::GetStatisticTableSchema());
8587

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

148+
// Indexes on pg_statistic
149+
dbc->pg_stat_.statistic_oid_index_ =
150+
Builder::BuildUniqueIndex(Builder::GetStatisticOidIndexSchema(oid), PgStatistic::STATISTIC_OID_INDEX_OID);
151+
146152
dbc->next_oid_.store(START_OID);
147153

148154
return dbc;
@@ -670,6 +676,28 @@ IndexSchema Builder::GetLanguageNameIndexSchema(db_oid_t db) {
670676
return schema;
671677
}
672678

679+
Schema Builder::GetStatisticTableSchema() {
680+
std::vector<Schema::Column> columns;
681+
682+
columns.emplace_back("starelid", type::TypeId::INTEGER, false,
683+
parser::ConstantValueExpression(type::TypeId::INTEGER));
684+
columns.back().SetOid(PgStatistic::STARELID.oid_);
685+
686+
columns.emplace_back("staattnum", type::TypeId::INTEGER, false,
687+
parser::ConstantValueExpression(type::TypeId::INTEGER));
688+
columns.back().SetOid(PgStatistic::STAATTNUM.oid_);
689+
690+
columns.emplace_back("stanullrows", type::TypeId::INTEGER, false,
691+
parser::ConstantValueExpression(type::TypeId::INTEGER));
692+
columns.back().SetOid(PgStatistic::STA_NULLROWS.oid_);
693+
694+
columns.emplace_back("stanumrows", type::TypeId::INTEGER, false,
695+
parser::ConstantValueExpression(type::TypeId::INTEGER));
696+
columns.back().SetOid(PgStatistic::STA_NUMROWS.oid_);
697+
698+
return Schema(columns);
699+
}
700+
673701
Schema Builder::GetProcTableSchema() {
674702
std::vector<Schema::Column> columns;
675703

@@ -795,6 +823,24 @@ IndexSchema Builder::GetProcNameIndexSchema(db_oid_t db) {
795823
return schema;
796824
}
797825

826+
IndexSchema Builder::GetStatisticOidIndexSchema(db_oid_t db) {
827+
std::vector<IndexSchema::Column> columns;
828+
829+
columns.emplace_back("starelid", type::TypeId::INTEGER, false,
830+
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID, PgStatistic::STARELID.oid_));
831+
columns.back().SetOid(indexkeycol_oid_t(1));
832+
833+
columns.emplace_back(
834+
"staattnum", type::TypeId::INTEGER, false,
835+
parser::ColumnValueExpression(db, PgStatistic::STATISTIC_TABLE_OID, PgStatistic::STAATTNUM.oid_));
836+
columns.back().SetOid(indexkeycol_oid_t(2));
837+
838+
// Primary
839+
IndexSchema schema(columns, storage::index::IndexType::BWTREE, true, true, false, true);
840+
841+
return schema;
842+
}
843+
798844
storage::index::Index *Builder::BuildUniqueIndex(const IndexSchema &key_schema, index_oid_t oid) {
799845
NOISEPAGE_ASSERT(key_schema.Unique(), "KeySchema must represent a unique index.");
800846
storage::index::IndexBuilder index_builder;
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#include "catalog/postgres/pg_statistic_impl.h"
2+
3+
#include "catalog/database_catalog.h"
4+
#include "catalog/index_schema.h"
5+
#include "catalog/postgres/builder.h"
6+
#include "catalog/postgres/pg_namespace.h"
7+
#include "catalog/schema.h"
8+
#include "storage/index/index.h"
9+
#include "storage/sql_table.h"
10+
11+
namespace noisepage::catalog::postgres {
12+
13+
PgStatisticImpl::PgStatisticImpl(db_oid_t db_oid) : db_oid_(db_oid) {}
14+
15+
void PgStatisticImpl::BootstrapPRIs() {
16+
const std::vector<col_oid_t> pg_statistic_all_oids{PgStatistic::PG_STATISTIC_ALL_COL_OIDS.cbegin(),
17+
PgStatistic::PG_STATISTIC_ALL_COL_OIDS.end()};
18+
pg_statistic_all_cols_pri_ = statistics_->InitializerForProjectedRow(pg_statistic_all_oids);
19+
pg_statistic_all_cols_prm_ = statistics_->ProjectionMapForOids(pg_statistic_all_oids);
20+
const std::vector<col_oid_t> statistic_oid_index_oids{PgStatistic::STARELID.oid_, PgStatistic::STAATTNUM.oid_};
21+
statistic_oid_index_pri_ = statistics_->InitializerForProjectedRow(statistic_oid_index_oids);
22+
statistic_oid_index_prm_ = statistics_->ProjectionMapForOids(statistic_oid_index_oids);
23+
}
24+
25+
void PgStatisticImpl::Bootstrap(common::ManagedPointer<transaction::TransactionContext> txn,
26+
common::ManagedPointer<DatabaseCatalog> dbc) {
27+
dbc->BootstrapTable(txn, PgStatistic::STATISTIC_TABLE_OID, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID,
28+
"pg_statistic", Builder::GetStatisticTableSchema(), statistics_);
29+
dbc->BootstrapIndex(txn, PgNamespace::NAMESPACE_CATALOG_NAMESPACE_OID, PgStatistic::STATISTIC_TABLE_OID,
30+
PgStatistic::STATISTIC_OID_INDEX_OID, "pg_statistic_index",
31+
Builder::GetStatisticOidIndexSchema(db_oid_), statistic_oid_index_);
32+
}
33+
34+
void PgStatisticImpl::CreateColumnStatistic(const common::ManagedPointer<transaction::TransactionContext> txn,
35+
const table_oid_t table_oid, const col_oid_t col_oid,
36+
const Schema::Column &col) {
37+
auto *const redo = txn->StageWrite(db_oid_, PgStatistic::STATISTIC_TABLE_OID, pg_statistic_all_cols_pri_);
38+
auto delta = common::ManagedPointer(redo->Delta());
39+
auto &pm = pg_statistic_all_cols_prm_;
40+
41+
// Prepare the PR for insertion.
42+
{
43+
PgStatistic::STARELID.Set(delta, pm, table_oid);
44+
PgStatistic::STAATTNUM.Set(delta, pm, col_oid);
45+
PgStatistic::STA_NULLROWS.Set(delta, pm, 0);
46+
PgStatistic::STA_NUMROWS.Set(delta, pm, 0);
47+
}
48+
const auto tuple_slot = statistics_->Insert(txn, redo);
49+
50+
const auto oid_pri = statistic_oid_index_->GetProjectedRowInitializer();
51+
auto oid_prm = statistic_oid_index_->GetKeyOidToOffsetMap();
52+
byte *const buffer = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());
53+
54+
// Insert into pg_statistic_index.
55+
{
56+
auto *pr = oid_pri.InitializeRow(buffer);
57+
pr->Set<table_oid_t, false>(oid_prm[indexkeycol_oid_t(1)], table_oid, false);
58+
pr->Set<col_oid_t, false>(oid_prm[indexkeycol_oid_t(2)], col_oid, false);
59+
60+
bool UNUSED_ATTRIBUTE result = statistic_oid_index_->InsertUnique(txn, *pr, tuple_slot);
61+
NOISEPAGE_ASSERT(result, "Assigned pg_statistic OIDs failed to be unique.");
62+
}
63+
64+
delete[] buffer;
65+
}
66+
67+
bool PgStatisticImpl::DeleteColumnStatistics(const common::ManagedPointer<transaction::TransactionContext> txn,
68+
const table_oid_t table_oid) {
69+
const auto &oid_pri = statistic_oid_index_->GetProjectedRowInitializer();
70+
const auto &oid_prm = statistic_oid_index_->GetKeyOidToOffsetMap();
71+
72+
byte *const key_buffer = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());
73+
byte *const key_buffer_2 = common::AllocationUtil::AllocateAligned(oid_pri.ProjectedRowSize());
74+
75+
// Look for the column statistic in pg_statistic_index.
76+
std::vector<storage::TupleSlot> index_results;
77+
{
78+
auto *pr_lo = oid_pri.InitializeRow(key_buffer);
79+
auto *pr_hi = oid_pri.InitializeRow(key_buffer_2);
80+
81+
// Low key (class, min col_oid_t)
82+
pr_lo->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid, false);
83+
pr_lo->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), col_oid_t(std::numeric_limits<uint32_t>::min()),
84+
false);
85+
86+
// High key (class + 1, max col_oid_t)
87+
pr_hi->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid + 1, false);
88+
pr_hi->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), col_oid_t(std::numeric_limits<uint32_t>::max()),
89+
false);
90+
91+
statistic_oid_index_->ScanAscending(*txn, storage::index::ScanType::Closed, 2, pr_lo, pr_hi, 0, &index_results);
92+
// TODO(WAN): Is there an assertion that we can make here?
93+
}
94+
95+
// Scan pg_statistic to get the columns.
96+
if (!index_results.empty()) {
97+
auto pr = common::ManagedPointer(statistic_oid_index_pri_.InitializeRow(key_buffer));
98+
for (const auto &slot : index_results) {
99+
auto UNUSED_ATTRIBUTE result = statistics_->Select(txn, slot, pr.Get());
100+
NOISEPAGE_ASSERT(result, "Index scan did a visibility check, so Select shouldn't fail at this point.");
101+
102+
auto &pm = statistic_oid_index_prm_;
103+
auto *col_oid = PgStatistic::STAATTNUM.Get(pr, pm);
104+
NOISEPAGE_ASSERT(col_oid != nullptr, "OID shouldn't be NULL.");
105+
106+
// Delete from pg_statistic.
107+
{
108+
txn->StageDelete(db_oid_, PgStatistic::STATISTIC_TABLE_OID, slot);
109+
if (!statistics_->Delete(txn, slot)) { // Failed to delete some column. Ask to abort.
110+
delete[] key_buffer;
111+
delete[] key_buffer_2;
112+
return false;
113+
}
114+
}
115+
116+
// Delete from pg_statistic_index.
117+
{
118+
auto *key_pr = oid_pri.InitializeRow(key_buffer_2);
119+
key_pr->Set<table_oid_t, false>(oid_prm.at(indexkeycol_oid_t(1)), table_oid, false);
120+
key_pr->Set<col_oid_t, false>(oid_prm.at(indexkeycol_oid_t(2)), *col_oid, false);
121+
statistic_oid_index_->Delete(txn, *key_pr, slot);
122+
}
123+
}
124+
}
125+
126+
delete[] key_buffer;
127+
delete[] key_buffer_2;
128+
return true;
129+
}
130+
131+
} // namespace noisepage::catalog::postgres

src/include/catalog/database_catalog.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "catalog/postgres/pg_core_impl.h"
1111
#include "catalog/postgres/pg_language_impl.h"
1212
#include "catalog/postgres/pg_proc_impl.h"
13+
#include "catalog/postgres/pg_statistic_impl.h"
1314
#include "catalog/postgres/pg_type_impl.h"
1415
#include "common/managed_pointer.h"
1516

@@ -192,6 +193,7 @@ class DatabaseCatalog {
192193
friend class postgres::PgLanguageImpl;
193194
friend class postgres::PgProcImpl;
194195
friend class postgres::PgTypeImpl;
196+
friend class postgres::PgStatisticImpl;
195197
///@}
196198
friend class Catalog; ///< Accesses write_lock_ (creating accessor) and TearDown (cleanup).
197199
friend class postgres::Builder; ///< Initializes DatabaseCatalog's tables.
@@ -209,6 +211,7 @@ class DatabaseCatalog {
209211
postgres::PgConstraintImpl pg_constraint_; ///< Constraints: pg_constraint.
210212
postgres::PgLanguageImpl pg_language_; ///< Languages: pg_language.
211213
postgres::PgProcImpl pg_proc_; ///< Procedures: pg_proc.
214+
postgres::PgStatisticImpl pg_stat_; ///< Statistics: pg_statistic.
212215

213216
/** @brief Create a new DatabaseCatalog. Does not create any tables until Bootstrap is called. */
214217
DatabaseCatalog(db_oid_t oid, common::ManagedPointer<storage::GarbageCollector> garbage_collector);

src/include/catalog/postgres/builder.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ class Builder {
9393
*/
9494
static Schema GetProcTableSchema();
9595

96+
/**
97+
* @return schema object for pg_statistic table
98+
*/
99+
static Schema GetStatisticTableSchema();
100+
96101
/**
97102
* @param db oid in which the indexed table exists
98103
* @return schema object for the oid index on pg_namespace
@@ -225,6 +230,12 @@ class Builder {
225230
*/
226231
static IndexSchema GetProcNameIndexSchema(db_oid_t db);
227232

233+
/**
234+
* @param db oid in which the indexed table exists
235+
* @return schema object for the table/oid index on pg_statistic
236+
*/
237+
static IndexSchema GetStatisticOidIndexSchema(db_oid_t db);
238+
228239
/**
229240
* Instantiate a new unique index with the given schema and oid
230241
* @param key_schema for the index
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#pragma once
2+
3+
#include <array>
4+
5+
#include "catalog/catalog_column_def.h"
6+
#include "catalog/catalog_defs.h"
7+
8+
namespace noisepage::storage {
9+
class RecoveryManager;
10+
} // namespace noisepage::storage
11+
12+
namespace noisepage::catalog::postgres {
13+
class Builder;
14+
class PgStatisticImpl;
15+
16+
/** The OIDs used by the NoisePage version of pg_statistic. */
17+
class PgStatistic {
18+
private:
19+
friend class storage::RecoveryManager;
20+
friend class Builder;
21+
friend class PgStatisticImpl;
22+
23+
static constexpr table_oid_t STATISTIC_TABLE_OID = table_oid_t(91);
24+
static constexpr index_oid_t STATISTIC_OID_INDEX_OID = index_oid_t(92);
25+
26+
/*
27+
* Column names of the form "STA[name]" are present in the PostgreSQL
28+
* catalog specification and columns of the form "STA_[name]" are
29+
* noisepage-specific additions.
30+
*/
31+
static constexpr CatalogColumnDef<table_oid_t, uint32_t> STARELID{col_oid_t{1}};
32+
static constexpr CatalogColumnDef<col_oid_t, uint32_t> STAATTNUM{col_oid_t{2}};
33+
static constexpr CatalogColumnDef<uint32_t, uint32_t> STA_NULLROWS{col_oid_t{3}};
34+
static constexpr CatalogColumnDef<uint32_t, uint32_t> STA_NUMROWS{col_oid_t{4}};
35+
36+
static constexpr uint8_t NUM_PG_STATISTIC_COLS = 4;
37+
38+
static constexpr std::array<col_oid_t, NUM_PG_STATISTIC_COLS> PG_STATISTIC_ALL_COL_OIDS = {
39+
STARELID.oid_, STAATTNUM.oid_, STA_NULLROWS.oid_, STA_NUMROWS.oid_};
40+
};
41+
42+
} // namespace noisepage::catalog::postgres

0 commit comments

Comments
 (0)