You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
System tables are special tables that provide information about Databend's internal state, such as databases, tables, functions, settings, etc. In this document, we will show you how to write a new system table for Databend using the credits table as an example.
5
+
System tables are tables that provide information about Databend's internal state, such as databases, tables, functions, and settings. If you're familiar with the Databend code structure and have basic knowledge about Rust, you can also create your own system tables as needed.
6
6
7
-
The credits table returns information about the upstream dependencies used by Databend, including their names, versions and licenses.
7
+
Creating a system table mainly involves defining the table information (table name and schema) and how to generate and retrieve data for the table. This can be done through implementing the trait `SyncSystemTable` or `AsyncSystemTable`.
8
8
9
-
## Prerequisites
9
+
This guide will show you how to create a new system table for Databend, using the table [system.credits](https://databend.rs/doc/sql-reference/system-tables/system-credits) as an example. The table provides information Databend's upstream dependencies and the code is located at `src/query/storage/system/src/credits_table.rs`.
10
10
11
-
To write a new system table for Databend, you need to have some basic knowledge of Rust programming language and Databend's code structure.
11
+
:::note
12
+
Databend suggests that you store the code for new system tables in the directory `src/query/storage/system/src/`. However, there may be situations where you cannot do so, such as issues related to the build process. In such cases, you can place it temporarily in a directory called `src/query/service/src/databases/system` (although this is not recommended).
13
+
:::
12
14
13
-
## Location
15
+
## Creating a System Table
14
16
15
-
The existing system tables for Databend are located in the `query/storage` directory. You should place your new system table file in this directory as well, unless there are some special build reasons that prevent you from doing so. In that case, you can temporarily place it in the `service/databases/system` directory (not recommended).
17
+
The following walks through the implementation of the table `system.credits` step by step.
16
18
17
-
## Definition
19
+
1. Define a struct for your system table that contains only the fields for storing the table information.
18
20
19
-
The definition of a system table mainly focuses on two aspects: one is the table information, which includes the table `name` and `schema`, etc.; the other is the data generation/retrieval logic for the table content. These two aspects correspond to two traits: `SyncSystemTable` and `AsyncSystemTable`. You need to implement one of these traits depending on whether your data retrieval involves asynchronous function calls or not.
20
-
21
-
## Implementation
22
-
23
-
In this section, we will walk through the implementation of the credits table step by step. The code file is located at `credits_table.rs`.
24
-
25
-
Firstly, you need to define a struct for your system table that contains only the fields for storing the table information. For example:
26
-
27
-
```rust
28
-
pubstructCreditsTable {
29
-
table_info:TableInfo,
30
-
}
31
-
```
32
-
33
-
Next, you need to implement a create method for your system table struct that takes a `table_id` as an argument and returns an `Arc<dyn Table>`. The `table_id` is generated by `sys_db_meta.next_table_id()` when creating a new system table.
34
-
35
-
```rust
36
-
pubfncreate(table_id:u64) ->Arc<dynTable>
37
-
```
21
+
```rust
22
+
pubstructCreditsTable {
23
+
table_info:TableInfo,
24
+
}
25
+
```
38
26
39
-
Insidethismethod, youneedtodefineaschemaforyoursystemtableusing `TableSchemaRefExt` and `TableField`.Theschemadescribesthestructureofyoursystemtablewithfieldnamesandtypesdependingonthedatayouwanttostoreinit.
3.Defineaschemaforyoursystemtableusing `TableSchemaRefExt` and `TableField`.Theschemadescribesthestructureofyoursystemtablewithfieldnamesandtypesdependingonthedatayouwanttostoreinit.
50
34
51
-
For string-type data, you can use `TableDataType::String`; other basic types are similar. But if you need to allow null values in your field, such as an optional 64-bit unsigned integer field, you can use `TableDataType::Nullable(Box::new(TableDataType::Number(NumberDataType::UInt64)))` instead. `TableDataType::Nullable` indicates that null values are allowed; `TableDataType::Number(NumberDataType::UInt64)` represents that the type is 64-bit unsigned integer.
35
+
Forstring-typedata, youcanuse `TableDataType::String`; otherbasictypesaresimilar.Butifyouneedtoallownullvaluesinyourfield, suchasanoptional64-bitunsignedintegerfield, youcanuse `TableDataType::Nullable(Box::new(TableDataType::Number(NumberDataType::UInt64)))` instead. `TableDataType::Nullable` indicates that null values are allowed; `TableDataType::Number(NumberDataType::UInt64)` representsthatthetypeis64-bitunsignedinteger.
52
36
53
-
After defining the schema, you need to define some metadata for your system table, such as description (`desc`), `name`, `meta`, etc. You can follow other existing examples and fill in these fields accordingly.
Finally, you need to create an instance of your system table struct with these fields and wrap it with either `SyncOneBlockSystemTable` or `AsyncOneBlockSystemTable` depending on whether your data retrieval logic is synchronous or asynchronous.
Next, you need to implement either `SyncSystemTable` or `AsyncSystemTable` trait for your system table struct. `SyncSystemTable` requires you to define `NAME` constant and implement four methods: `get_table_info()`, `get_full_data()`, `get_partitions()` and `truncate()`. However, the last two methods have default implementations, so you don't need to implement them yourself in most cases. (`AsyncSystemTable`is similar, but it doesn't have `truncate()` method.)
63
+
5.Createaninstanceofyoursystemtablestructwiththesefieldsandwrapitwitheither `SyncOneBlockSystemTable` or `AsyncOneBlockSystemTable`, dependingonwhetheryourdataretrievalissynchronousorasynchronous.
76
64
77
-
`NAME` constant follows the format of `system.<name>`.
`get_full_data()` method is the most important part, because it contains the logic for generating or retrieving the data for your system table. The credits table has three fields that are similar, so we will only show the license field as an example.
75
+
```rust
76
+
fnget_table_info(&self) ->&TableInfo {
77
+
&self.table_info
78
+
}
79
+
```
92
80
93
-
The license field information is obtained from an environment variable named `DATABEND_CREDITS_LICENSES` (see `common-building`). Each data item is separated by a comma.
String-type columns are eventually converted from `Vec<Vec<u8>>`, where each string needs to be converted to `Vec<u8>`. So we use `.as_bytes().to_vec()` to do this conversion when iterating over the data.
83
+
Thelicensefieldinformationisobtainedfromanenvironmentvariablenamed `DATABEND_CREDITS_LICENSES` (see `common-building`).Eachdataitemisseparatedbyacomma.
String-typecolumnsareeventuallyconvertedfrom `Vec<Vec<u8>>`, whereeachstringneedstobeconvertedto `Vec<u8>`.Soweuse `.as_bytes().to_vec()` to do this conversion when iterating over the data.
103
86
104
-
After getting all the data, you can return them in a `DataBlock` format. For non-null types, use `from_data`; for nullable types, use `from_opt_data`.
87
+
```rust
88
+
let licenses:Vec<Vec<u8>> = env!("DATABEND_CREDITS_LICENSES")
The tests for system tables are currently located at `tests/it/storages/system.rs`.
116
+
## TestingaNewSystemTable
131
117
132
-
For tables whose content does not change frequently, you can use Golden File testing. Its logic is to write the corresponding table into a specified file and compare it with an expected file. If they match, then the test passes; otherwise, it fails.
For tables whose content may change dynamically or depend on external factors, there is a lack of sufficient testing methods. You can choose to test the parts that have relatively fixed patterns, such as the number of rows and columns; or you can verify whether the output contains specific content.
151
-
152
-
For example:
132
+
For tables with dynamically changing content or external dependencies, testing methods are limited. You can test relatively fixed patterns such as the number of rows and columns, or verify if the output contains specific content. For example:
In this document, we have shown you how to write a new system table for Databend using the credits table as an example. We hope this document helps you understand the basic steps and principles of creating a system table for Databend. If you have any questions or feedback, please feel free to contact us on GitHub or Slack. Thank you for your interest and contribution to Databend!
0 commit comments