catalog/system_schema/
pg_catalog.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15mod pg_catalog_memory_table;
16mod pg_class;
17mod pg_database;
18mod pg_namespace;
19mod table_names;
20
21use std::collections::HashMap;
22use std::sync::{Arc, LazyLock, Weak};
23
24use common_catalog::consts::{self, DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME, PG_CATALOG_NAME};
25use datatypes::schema::ColumnSchema;
26use lazy_static::lazy_static;
27use paste::paste;
28use pg_catalog_memory_table::get_schema_columns;
29use pg_class::PGClass;
30use pg_database::PGDatabase;
31use pg_namespace::PGNamespace;
32use session::context::{Channel, QueryContext};
33use table::TableRef;
34pub use table_names::*;
35
36use self::pg_namespace::oid_map::{PGNamespaceOidMap, PGNamespaceOidMapRef};
37use crate::system_schema::memory_table::MemoryTable;
38use crate::system_schema::utils::tables::u32_column;
39use crate::system_schema::{SystemSchemaProvider, SystemSchemaProviderInner, SystemTableRef};
40use crate::CatalogManager;
41
42lazy_static! {
43    static ref MEMORY_TABLES: &'static [&'static str] = &[table_names::PG_TYPE];
44}
45
46/// The column name for the OID column.
47/// The OID column is a unique identifier of type u32 for each object in the database.
48const OID_COLUMN_NAME: &str = "oid";
49
50fn oid_column() -> ColumnSchema {
51    u32_column(OID_COLUMN_NAME)
52}
53
54/// [`PGCatalogProvider`] is the provider for a schema named `pg_catalog`, it is not a catalog.
55pub struct PGCatalogProvider {
56    catalog_name: String,
57    catalog_manager: Weak<dyn CatalogManager>,
58    tables: HashMap<String, TableRef>,
59
60    // Workaround to store mapping of schema_name to a numeric id
61    namespace_oid_map: PGNamespaceOidMapRef,
62}
63
64impl SystemSchemaProvider for PGCatalogProvider {
65    fn tables(&self) -> &HashMap<String, TableRef> {
66        assert!(!self.tables.is_empty());
67
68        &self.tables
69    }
70}
71
72// TODO(j0hn50n133): Not sure whether to avoid duplication with `information_schema` or not.
73macro_rules! setup_memory_table {
74    ($name: expr) => {
75        paste! {
76            {
77                let (schema, columns) = get_schema_columns($name);
78                Some(Arc::new(MemoryTable::new(
79                    consts::[<PG_CATALOG_ $name  _TABLE_ID>],
80                    $name,
81                    schema,
82                    columns
83                )) as _)
84            }
85        }
86    };
87}
88
89impl PGCatalogProvider {
90    pub fn new(catalog_name: String, catalog_manager: Weak<dyn CatalogManager>) -> Self {
91        let mut provider = Self {
92            catalog_name,
93            catalog_manager,
94            tables: HashMap::new(),
95            namespace_oid_map: Arc::new(PGNamespaceOidMap::new()),
96        };
97        provider.build_tables();
98        provider
99    }
100
101    fn build_tables(&mut self) {
102        // SECURITY NOTE:
103        // Must follow the same security rules as [`InformationSchemaProvider::build_tables`].
104        let mut tables = HashMap::new();
105        // TODO(J0HN50N133): modeling the table_name as a enum type to get rid of expect/unwrap here
106        // It's safe to unwrap here because we are sure that the constants have been handle correctly inside system_table.
107        for name in MEMORY_TABLES.iter() {
108            tables.insert(name.to_string(), self.build_table(name).expect(name));
109        }
110        tables.insert(
111            PG_NAMESPACE.to_string(),
112            self.build_table(PG_NAMESPACE).expect(PG_NAMESPACE),
113        );
114        tables.insert(
115            PG_CLASS.to_string(),
116            self.build_table(PG_CLASS).expect(PG_NAMESPACE),
117        );
118        tables.insert(
119            PG_DATABASE.to_string(),
120            self.build_table(PG_DATABASE).expect(PG_DATABASE),
121        );
122        self.tables = tables;
123    }
124}
125
126impl SystemSchemaProviderInner for PGCatalogProvider {
127    fn schema_name() -> &'static str {
128        PG_CATALOG_NAME
129    }
130
131    fn system_table(&self, name: &str) -> Option<SystemTableRef> {
132        match name {
133            table_names::PG_TYPE => setup_memory_table!(PG_TYPE),
134            table_names::PG_NAMESPACE => Some(Arc::new(PGNamespace::new(
135                self.catalog_name.clone(),
136                self.catalog_manager.clone(),
137                self.namespace_oid_map.clone(),
138            ))),
139            table_names::PG_CLASS => Some(Arc::new(PGClass::new(
140                self.catalog_name.clone(),
141                self.catalog_manager.clone(),
142                self.namespace_oid_map.clone(),
143            ))),
144            table_names::PG_DATABASE => Some(Arc::new(PGDatabase::new(
145                self.catalog_name.clone(),
146                self.catalog_manager.clone(),
147                self.namespace_oid_map.clone(),
148            ))),
149            _ => None,
150        }
151    }
152
153    fn catalog_name(&self) -> &str {
154        &self.catalog_name
155    }
156}
157
158/// Provide query context to call the [`CatalogManager`]'s method.
159static PG_QUERY_CTX: LazyLock<QueryContext> = LazyLock::new(|| {
160    QueryContext::with_channel(DEFAULT_CATALOG_NAME, DEFAULT_SCHEMA_NAME, Channel::Postgres)
161});
162
163fn query_ctx() -> Option<&'static QueryContext> {
164    Some(&PG_QUERY_CTX)
165}