@@ -63,12 +63,12 @@ Databend uses the latest techniques in vectorized query processing to allow you
- __Blazing Performance__
- Databend leverages data-level parallelism(Vectorized Query Execution) and instruction-level parallelism(SIMD) technology, offering blazing performance data analytics.
+ Databend leverages data-level parallelism(Vectorized Query Execution) and instruction-level parallelism(SIMD) technology, offering [blazing performance](https://benchmark.clickhouse.com/) data analytics.
- __Git-like MVCC Storage__
- Databend stores data with snapshots. It's easy to query, clone, and restore historical data in tables.
+ [Databend stores data with snapshots](https://databend.rs/doc/sql-commands/ddl/table/optimize-table#what-are-snapshot-segment-and-block), enabling users to effortlessly query, clone, or restore data from any history timepoint.
- __Support for Semi-Structured Data__
@@ -78,7 +78,7 @@ Databend uses the latest techniques in vectorized query processing to allow you
- __MySQL/ClickHouse Compatible__
- Databend is ANSI SQL compliant and MySQL/ClickHouse wire protocol compatible, making it easy to connect with existing tools([MySQL Client](https://databend.rs/doc/integrations/api/mysql-handler), [ClickHouse Client](https://databend.rs/doc/integrations/api/clickhouse-handler), [Vector](https://vector.dev/), [DBeaver](https://dbeaver.com/), [Jupyter](https://databend.rs/doc/integrations/gui-tool/jupyter), [JDBC](https://databend.rs/doc/develop), etc.).
+ Databend is ANSI SQL compliant and MySQL/ClickHouse wire protocol compatible, making it easy to connect with existing tools([MySQL Client](https://databend.rs/doc/integrations/api/mysql-handler), [ClickHouse HTTP Handler](https://databend.rs/doc/integrations/api/clickhouse-handler), [Vector](https://vector.dev/), [DBeaver](https://dbeaver.com/), [Jupyter](https://databend.rs/doc/integrations/gui-tool/jupyter), [JDBC](https://databend.rs/doc/develop), etc.).
- __Easy to Use__
@@ -122,7 +122,7 @@ docker run --net=host datafuselabs/databend
### Connecting to Databend
- [How to Connect Databend with MySQL Client](https://databend.rs/doc/integrations/api/mysql-handler)
-- [How to Connect Databend with ClickHouse Client](https://databend.rs/doc/integrations/api/clickhouse-handler)
+- [How to Connect Databend with ClickHouse HTTP Handler](https://databend.rs/doc/integrations/api/clickhouse-handler)
- [How to Connect Databend with DBeaver SQL IDE](https://databend.rs/doc/integrations/gui-tool/dbeaver)
- [How to Execute Queries in Python](https://databend.rs/doc/develop/python)
- [How to Query Databend in Jupyter Notebooks](https://databend.rs/doc/integrations/gui-tool/jupyter)
diff --git a/benchmark/tpch/prepare_fuse_table.sh b/benchmark/tpch/prepare_fuse_table.sh
index 172c3f4d7063b..e3d87b0e91306 100644
--- a/benchmark/tpch/prepare_fuse_table.sh
+++ b/benchmark/tpch/prepare_fuse_table.sh
@@ -33,7 +33,7 @@ echo "CREATE TABLE IF NOT EXISTS part
p_type STRING not null,
p_size INTEGER not null,
p_container STRING not null,
- p_retailprice DOUBLE not null,
+ p_retailprice DECIMAL(15, 2) not null,
p_comment STRING not null
)" | $MYSQL_CLIENT_CONNECT
@@ -44,7 +44,7 @@ echo "CREATE TABLE IF NOT EXISTS supplier
s_address STRING not null,
s_nationkey INTEGER not null,
s_phone STRING not null,
- s_acctbal DOUBLE not null,
+ s_acctbal DECIMAL(15, 2) not null,
s_comment STRING not null
)" | $MYSQL_CLIENT_CONNECT
@@ -53,7 +53,7 @@ echo "CREATE TABLE IF NOT EXISTS partsupp
ps_partkey BIGINT not null,
ps_suppkey BIGINT not null,
ps_availqty BIGINT not null,
- ps_supplycost DOUBLE not null,
+ ps_supplycost DECIMAL(15, 2) not null,
ps_comment STRING not null
)" | $MYSQL_CLIENT_CONNECT
@@ -64,7 +64,7 @@ echo "CREATE TABLE IF NOT EXISTS customer
c_address STRING not null,
c_nationkey INTEGER not null,
c_phone STRING not null,
- c_acctbal DOUBLE not null,
+ c_acctbal DECIMAL(15, 2) not null,
c_mktsegment STRING not null,
c_comment STRING not null
)" | $MYSQL_CLIENT_CONNECT
@@ -74,7 +74,7 @@ echo "CREATE TABLE IF NOT EXISTS orders
o_orderkey BIGINT not null,
o_custkey BIGINT not null,
o_orderstatus STRING not null,
- o_totalprice DOUBLE not null,
+ o_totalprice DECIMAL(15, 2) not null,
o_orderdate DATE not null,
o_orderpriority STRING not null,
o_clerk STRING not null,
@@ -88,10 +88,10 @@ echo "CREATE TABLE IF NOT EXISTS lineitem
l_partkey BIGINT not null,
l_suppkey BIGINT not null,
l_linenumber BIGINT not null,
- l_quantity DOUBLE not null,
- l_extendedprice DOUBLE not null,
- l_discount DOUBLE not null,
- l_tax DOUBLE not null,
+ l_quantity DECIMAL(15, 2) not null,
+ l_extendedprice DECIMAL(15, 2) not null,
+ l_discount DECIMAL(15, 2) not null,
+ l_tax DECIMAL(15, 2) not null,
l_returnflag STRING not null,
l_linestatus STRING not null,
l_shipdate DATE not null,
diff --git a/benchmark/tpch/prepare_native_table.sh b/benchmark/tpch/prepare_native_table.sh
index 85d1adc7ab946..b75e22ec1510d 100644
--- a/benchmark/tpch/prepare_native_table.sh
+++ b/benchmark/tpch/prepare_native_table.sh
@@ -33,7 +33,7 @@ echo "CREATE TABLE IF NOT EXISTS part
p_type STRING not null,
p_size INTEGER not null,
p_container STRING not null,
- p_retailprice DOUBLE not null,
+ p_retailprice DECIMAL(15, 2) not null,
p_comment STRING not null
) storage_format = 'native' compression = 'lz4'" | $MYSQL_CLIENT_CONNECT
@@ -44,7 +44,7 @@ echo "CREATE TABLE IF NOT EXISTS supplier
s_address STRING not null,
s_nationkey INTEGER not null,
s_phone STRING not null,
- s_acctbal DOUBLE not null,
+ s_acctbal DECIMAL(15, 2) not null,
s_comment STRING not null
) storage_format = 'native' compression = 'lz4'" | $MYSQL_CLIENT_CONNECT
@@ -53,7 +53,7 @@ echo "CREATE TABLE IF NOT EXISTS partsupp
ps_partkey BIGINT not null,
ps_suppkey BIGINT not null,
ps_availqty BIGINT not null,
- ps_supplycost DOUBLE not null,
+ ps_supplycost DECIMAL(15, 2) not null,
ps_comment STRING not null
) storage_format = 'native' compression = 'lz4'" | $MYSQL_CLIENT_CONNECT
@@ -64,7 +64,7 @@ echo "CREATE TABLE IF NOT EXISTS customer
c_address STRING not null,
c_nationkey INTEGER not null,
c_phone STRING not null,
- c_acctbal DOUBLE not null,
+ c_acctbal DECIMAL(15, 2) not null,
c_mktsegment STRING not null,
c_comment STRING not null
)" | $MYSQL_CLIENT_CONNECT
@@ -74,7 +74,7 @@ echo "CREATE TABLE IF NOT EXISTS orders
o_orderkey BIGINT not null,
o_custkey BIGINT not null,
o_orderstatus STRING not null,
- o_totalprice DOUBLE not null,
+ o_totalprice DECIMAL(15, 2) not null,
o_orderdate DATE not null,
o_orderpriority STRING not null,
o_clerk STRING not null,
@@ -88,10 +88,10 @@ echo "CREATE TABLE IF NOT EXISTS lineitem
l_partkey BIGINT not null,
l_suppkey BIGINT not null,
l_linenumber BIGINT not null,
- l_quantity DOUBLE not null,
- l_extendedprice DOUBLE not null,
- l_discount DOUBLE not null,
- l_tax DOUBLE not null,
+ l_quantity DECIMAL(15, 2) not null,
+ l_extendedprice DECIMAL(15, 2) not null,
+ l_discount DECIMAL(15, 2) not null,
+ l_tax DECIMAL(15, 2) not null,
l_returnflag STRING not null,
l_linestatus STRING not null,
l_shipdate DATE not null,
diff --git a/docker/it-hive/hadoop-hive.env b/docker/it-hive/hadoop-hive.env
index 965a03c6def3d..601581818d163 100644
--- a/docker/it-hive/hadoop-hive.env
+++ b/docker/it-hive/hadoop-hive.env
@@ -4,13 +4,13 @@ HIVE_SITE_CONF_javax_jdo_option_ConnectionUserName=hive
HIVE_SITE_CONF_javax_jdo_option_ConnectionPassword=hive
HIVE_SITE_CONF_datanucleus_autoCreateSchema=false
HIVE_SITE_CONF_hive_metastore_uris=thrift://hive-metastore:9083
-HDFS_CONF_dfs_namenode_datanode_registration_ip___hostname___check=false
CORE_CONF_fs_defaultFS=hdfs://namenode:8020
CORE_CONF_hadoop_http_staticuser_user=root
CORE_CONF_hadoop_proxyuser_hue_hosts=*
CORE_CONF_hadoop_proxyuser_hue_groups=*
+HDFS_CONF_dfs_namenode_datanode_registration_ip___hostname___check=false
HDFS_CONF_dfs_webhdfs_enabled=true
HDFS_CONF_dfs_permissions_enabled=false
@@ -27,4 +27,4 @@ YARN_CONF_yarn_resourcemanager_hostname=resourcemanager
YARN_CONF_yarn_timeline___service_hostname=historyserver
YARN_CONF_yarn_resourcemanager_address=resourcemanager:8032
YARN_CONF_yarn_resourcemanager_scheduler_address=resourcemanager:8030
-YARN_CONF_yarn_resourcemanager_resource__tracker_address=resourcemanager:8031
\ No newline at end of file
+YARN_CONF_yarn_resourcemanager_resource__tracker_address=resourcemanager:8031
diff --git a/docs/doc/00-overview/index.md b/docs/doc/00-overview/index.md
index 3942e10743f16..b1e6c76b20add 100644
--- a/docs/doc/00-overview/index.md
+++ b/docs/doc/00-overview/index.md
@@ -19,7 +19,7 @@ import TabItem from '@theme/TabItem';
- Blazing-fast data analytics on object storage.
-- Leverages data-level parallelism and instruction-level parallelism technologies for optimal performance.
+- Leverages data-level parallelism and instruction-level parallelism technologies for [optimal performance]](https://benchmark.clickhouse.com/).
- Supports Git-like MVCC storage for easy querying, cloning, and restoration of historical data.
- No indexes to build, no manual tuning, and no need to figure out partitions or shard data.
@@ -29,7 +29,7 @@ import TabItem from '@theme/TabItem';
- Compatible with MySQL / ClickHouse.
- ANSI SQL compliant.
-- Easy connection with existing tools such as [MySQL Client](https://databend.rs/doc/integrations/api/mysql-handler), [ClickHouse Client](https://databend.rs/doc/integrations/api/clickhouse-handler), [Vector](https://vector.dev/), [DBeaver](https://dbeaver.com/), [Jupyter](https://databend.rs/doc/integrations/gui-tool/jupyter), [JDBC](https://databend.rs/doc/develop), and more.
+- Easy connection with existing tools such as [MySQL Client](https://databend.rs/doc/integrations/api/mysql-handler), [ClickHouse HTTP Handler](https://databend.rs/doc/integrations/api/clickhouse-handler), [Vector](https://vector.dev/), [DBeaver](https://dbeaver.com/), [Jupyter](https://databend.rs/doc/integrations/gui-tool/jupyter), [JDBC](https://databend.rs/doc/develop), and more.
diff --git a/docs/doc/01-guides/index.md b/docs/doc/01-guides/index.md
index 972f47683ecc3..08962ac5e1383 100644
--- a/docs/doc/01-guides/index.md
+++ b/docs/doc/01-guides/index.md
@@ -1,5 +1,5 @@
---
-title: Getting Started Tutorials
+title: Get Started
---
These tutorials are intended to help you get started with Databend:
@@ -16,13 +16,13 @@ These tutorials are intended to help you get started with Databend:
## Connecting to Databend
* [How to Connect Databend with MySQL Client](../11-integrations/00-api/01-mysql-handler.md)
-* [How to Connect Databend with ClickHouse Client](../11-integrations/00-api/02-clickhouse-handler.md)
+* [How to Connect Databend with ClickHouse HTTP Handler](../11-integrations/00-api/02-clickhouse-handler.md)
* [How to Connect Databend with REST API](../11-integrations/00-api/00-rest.md)
* [How to Connect Databend with DBeaver SQL IDE](../11-integrations/20-gui-tool/01-dbeaver.md)
-* [How to Execute Queries in Python](../20-develop/01-python.md)
+* [How to Execute Queries in Python](../03-develop/01-python.md)
* [How to Query Databend in Jupyter Notebooks](../11-integrations/20-gui-tool/00-jupyter.md)
-* [How to Execute Queries in Golang](../20-develop/00-golang.md)
-* [How to Execute Queries in Node.js](../20-develop/02-nodejs.md)
+* [How to Execute Queries in Golang](../03-develop/00-golang.md)
+* [How to Execute Queries in Node.js](../03-develop/02-nodejs.md)
## Loading Data into Databend
@@ -84,4 +84,4 @@ These tutorials are intended to help you get started with Databend:
## Performance
-* [How to Benchmark Databend](../21-use-cases/01-analyze-ontime-with-databend-on-ec2-and-s3.md)
\ No newline at end of file
+* [How to Benchmark Databend](../21-use-cases/01-analyze-ontime-with-databend-on-ec2-and-s3.md)
diff --git a/docs/doc/02-cloud/index.md b/docs/doc/02-cloud/index.md
index 8825618d15a84..1695fb5a7ea85 100644
--- a/docs/doc/02-cloud/index.md
+++ b/docs/doc/02-cloud/index.md
@@ -1,24 +1,22 @@
---
-title: Try Databend Cloud (Beta) Free
+title: Try Databend Cloud Free
sidebar_label: Databend Cloud
---
[Databend Cloud](https://www.databend.com) is a powerful data cloud for everyone, which is built on top of the open-source project Databend with **Simplicity**, **Elasticity**, **Security**, and **Low Cost**.
-- [Get Started for Free](https://www.databend.com/apply)
-- [Databend Cloud Documentation](https://www.databend.com/docs)
-- [Architecture Overview](https://www.databend.com/docs)
-- [Organizations & Users](https://www.databend.com/docs/organizations-users/manage-your-organization/)
-- [Working with Warehouses](https://www.databend.com/docs/working-with-warehouses/understanding-warehouse)
-- [Connecting to BI Tools](https://www.databend.com/docs/connecting-to-bi-tools/about-this-guide)
-- [Developing with Databend Cloud](https://www.databend.com/docs/developing-with-databend-cloud/about-this-guide)
+## Databend Cloud Architecture
+
+
+
+
## Create a Databend Cloud Account
Databend Cloud is now in private beta. To create a Databend Cloud account, go to https://www.databend.com/apply to apply for beta access.
-## Log in to Your Account
+## Logging in to Your Account
To log in to your account, go to https://app.databend.com.
@@ -29,14 +27,16 @@ To log in to your account, go to https://app.databend.com.
### Warehouses
-Serverless warehouses can be automatically suspended in case of no activities for a specific period.
+Databend Cloud offers serverless warehouses that can be automatically suspended if there is no activity for a specific period.
+
+A demonstration of how Databend Cloud's warehouses work is shown below.
### Databases
-This page shows a list of your databases:
+This page shows a list of your databases in Databend Cloud:
@@ -46,9 +46,10 @@ Worksheets is a powerful SQL editor where you can run SQL queries. For example,
-### Connect to a Serverless Warehouse on Databend Cloud
+### Connect
Databend Cloud provides a connection string for your applications to connect to it:
+
```shell
@@ -60,10 +61,6 @@ Run query with curl:
curl --user 'cloudapp:password' --data-binary 'SHOW TABLES' 'https://--.ch.aws-us-east-2.default.databend.com?database=default'
```
-## Community
+## Databend Cloud Documentation
-- [Slack](https://link.databend.rs/join-slack) (For live discussion with the Community)
-- [Github](https://github.com/datafuselabs/databend) (Feature/Bug reports, Contributions)
-- [Twitter](https://twitter.com/DatabendLabs) (Get the news fast)
-- [Weekly](https://weekly.databend.rs/) (A weekly newsletter about Databend)
-- [I'm feeling lucky](https://link.databend.rs/i-m-feeling-lucky) (Pick up a good first issue now!)
\ No newline at end of file
+ - [Databend Cloud Documentation](https://docs.databend.com/)
\ No newline at end of file
diff --git a/docs/doc/03-develop/00-golang.md b/docs/doc/03-develop/00-golang.md
new file mode 100644
index 0000000000000..580d6c73f5e6f
--- /dev/null
+++ b/docs/doc/03-develop/00-golang.md
@@ -0,0 +1,164 @@
+---
+title: Developing with Databend using Golang
+sidebar_label: Golang
+description:
+ Develop with Databend using Golang.
+---
+
+Databend offers a driver (databend-go) written in Golang, which facilitates the development of applications using the Golang programming language and establishes connectivity with Databend.
+
+For installation instructions, examples, and the source code, see the GitHub [databend-go](https://github.com/databendcloud/databend-go) repo.
+
+In the following tutorial, you'll learn how to utilize the driver `databend-go` to develop your applications. The tutorial will walk you through creating a SQL user in Databend and then writing Golang code to create a table, insert data, and perform data queries.
+
+## Tutorial: Developing with Databend using Golang
+
+Before you start, make sure you have successfully installed Databend. For how to install Databend, see [How to deploy Databend](/doc/deploy).
+
+### Step 1. Prepare a SQL User Account
+
+To connect your program to Databend and execute SQL operations, you must provide a SQL user account with appropriate privileges in your code. Create one in Databend if needed, and ensure that the SQL user has only the necessary privileges for security.
+
+This tutorial uses a SQL user named 'user1' with password 'abc123' as an example. As the program will write data into Databend, the user needs ALL privileges. For how to manage SQL users and their privileges, see https://databend.rs/doc/reference/sql/ddl/user.
+
+```sql
+CREATE USER user1 IDENTIFIED BY 'abc123';
+GRANT ALL on *.* TO user1;
+```
+
+### Step 2. Write a Golang Program
+
+In this step, you'll create a simple Golang program that communicates with Databend. The program will involve tasks such as creating a table, inserting data, and executing data queries.
+
+1. Copy and paste the following code to the file `main.go`:
+
+:::note
+The value of `hostname` in the code below must align with your HTTP handler settings for Databend query service.
+:::
+
+```go title='main.go'
+package main
+
+import (
+ "database/sql"
+ "fmt"
+ "log"
+
+ _ "github.com/databendcloud/databend-go"
+)
+
+const (
+ username = "user1"
+ password = "abc123"
+ hostname = "127.0.0.1:8000"
+)
+
+type Book struct {
+ Title string
+ Author string
+ Date string
+}
+
+func dsn() string {
+ return fmt.Sprintf("http://%s:%s@%s", username, password, hostname)
+}
+
+func main() {
+ db, err := sql.Open("databend", dsn())
+
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer db.Close()
+
+ err = db.Ping()
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Connected")
+
+ // Create db if do not exist
+ dbSql := "CREATE DATABASE IF NOT EXISTS book_db"
+ _, err = db.Exec(dbSql)
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Create database book_db success")
+
+ // Use book_db database
+ _, err = db.Exec("USE book_db")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Create table.
+ sql := "create table if not exists books(title VARCHAR, author VARCHAR, date VARCHAR)"
+ _, err = db.Exec(sql)
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Create table: books")
+
+ // Insert 1 row.
+ _, err = db.Exec("INSERT INTO books VALUES(?, ?, ?)", "mybook", "author", "2022")
+ if err != nil {
+ log.Fatal(err)
+ }
+ log.Println("Insert 1 row")
+
+ // Select.
+ res, err := db.Query("SELECT * FROM books")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ for res.Next() {
+ var book Book
+ err := res.Scan(&book.Title, &book.Author, &book.Date)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ log.Printf("Select:%v", book)
+ }
+ db.Exec("drop table books")
+ db.Exec("drop database book_db")
+}
+```
+
+2. Install dependencies.
+
+```shell
+go mod init databend-golang
+```
+
+```text title='go.mod'
+module databend-golang
+
+go 1.20
+
+require github.com/databendcloud/databend-go v0.3.10
+
+require (
+ github.com/BurntSushi/toml v1.2.1 // indirect
+ github.com/avast/retry-go v3.0.0+incompatible // indirect
+ github.com/google/uuid v1.3.0 // indirect
+ github.com/pkg/errors v0.9.1 // indirect
+ github.com/sirupsen/logrus v1.9.0 // indirect
+ golang.org/x/sys v0.5.0 // indirect
+)
+```
+
+3. Run the program.
+
+```shell
+go run main.go
+```
+
+```text title='Outputs'
+2023/02/24 23:57:31 Connected
+2023/02/24 23:57:31 Create database book_db success
+2023/02/24 23:57:31 Create table: books
+2023/02/24 23:57:31 Insert 1 row
+2023/02/24 23:57:31 Select:{mybook author 2022}
+```
\ No newline at end of file
diff --git a/docs/doc/03-develop/01-python.md b/docs/doc/03-develop/01-python.md
new file mode 100644
index 0000000000000..6f17cbf1e362e
--- /dev/null
+++ b/docs/doc/03-develop/01-python.md
@@ -0,0 +1,115 @@
+---
+title: Developing with Databend using Python
+sidebar_label: Python
+description:
+ Develop with Databend using Python.
+---
+import GetLatest from '@site/src/components/GetLatest';
+
+Databend offers the following options enabling you to develop applications using the Python programming language and establish connectivity with Databend:
+
+- [databend-py](https://github.com/databendcloud/databend-py): Python driver, including support for native HTTP interfaces.
+- [databend-sqlalchemy](https://github.com/databendcloud/databend-sqlalchemy): Databend SQLAlchemy dialect.
+
+Click the links above for their installation instructions, examples, and the source code on GitHub.
+
+In the following tutorial, you'll learn how to utilize the available options above to develop your applications. The tutorial will walk you through creating a SQL user in Databend and then writing Python code to create a table, insert data, and perform data queries.
+
+## Tutorial: Developing with Databend using Python
+
+Before you start, make sure you have successfully installed Databend. For how to install Databend, see [How to deploy Databend](/doc/deploy).
+
+### Step 1. Prepare a SQL User Account
+
+To connect your program to Databend and execute SQL operations, you must provide a SQL user account with appropriate privileges in your code. Create one in Databend if needed, and ensure that the SQL user has only the necessary privileges for security.
+
+This tutorial uses a SQL user named 'user1' with password 'abc123' as an example. As the program will write data into Databend, the user needs ALL privileges. For how to manage SQL users and their privileges, see https://databend.rs/doc/reference/sql/ddl/user.
+
+```sql
+CREATE USER user1 IDENTIFIED BY 'abc123';
+GRANT ALL on *.* TO user1;
+```
+
+### Step 2. Write a Python Program
+
+In this step, you'll create a simple Python program that communicates with Databend. The program will involve tasks such as creating a table, inserting data, and executing data queries.
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+
+
+
+1. Install databend-py.
+
+```shell
+pip install databend-py
+```
+2. Copy and paste the following code to the file `main.py`:
+
+```python title='main.py'
+#!/usr/bin/env python3
+
+from databend_py import Client
+
+client = Client('user1:abc123@127.0.0.1', port=8000, secure=False)
+
+# Create database, table.
+client.execute("CREATE DATABASE IF NOT EXISTS book_db")
+client.execute("USE book_db")
+client.execute("CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)")
+
+# Insert new book.
+client.execute("INSERT INTO books VALUES('mybook', 'author', '2022')")
+
+# Query.
+_, results = client.execute("SELECT * FROM books")
+for (title, author, date) in results:
+ print("{} {} {}".format(title, author, date))
+client.execute('drop table books')
+client.execute('drop database book_db')
+```
+
+3. Run `python main.py`:
+
+```text
+mybook author 2022
+```
+
+
+
+
+1. Install databend-sqlalchemy.
+
+```shell
+pip install databend-sqlalchemy
+```
+
+2. Copy and paste the following code to the file `main.py`:
+
+```python title='main.py'
+#!/usr/bin/env python3
+
+from databend_sqlalchemy import connector
+
+conn = connector.connect(f"http://user1:abc123@127.0.0.1:8000").cursor()
+conn.execute("CREATE DATABASE IF NOT EXISTS book_db")
+conn.execute("USE book_db")
+conn.execute("CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)")
+conn.execute("INSERT INTO books VALUES('mybook', 'author', '2022')")
+conn.execute('SELECT * FROM books')
+results = conn.fetchall()
+for result in results:
+ print(result)
+conn.execute('drop table books')
+conn.execute('drop database book_db')
+```
+
+3. Run `python main.py`:
+
+```text
+('mybook', 'author', '2022')
+```
+
+
+
\ No newline at end of file
diff --git a/docs/doc/03-develop/02-nodejs.md b/docs/doc/03-develop/02-nodejs.md
new file mode 100644
index 0000000000000..16149399e25ab
--- /dev/null
+++ b/docs/doc/03-develop/02-nodejs.md
@@ -0,0 +1,90 @@
+---
+title: Developing with Databend using Node.js
+sidebar_label: Node.js
+description:
+ Develop with Databend using Node.js.
+---
+
+In the following tutorial, you'll learn how to develop a Node.js application that communicates with Databend. The tutorial will walk you through creating a SQL user in Databend and then writing code to create a table, insert data, and perform data queries.
+
+## Tutorial: Developing with Databend using Node.js
+
+Before you start, make sure you have successfully installed Databend. For how to install Databend, see [How to deploy Databend](/doc/deploy).
+
+### Step 1. Prepare a SQL User Account
+
+To connect your program to Databend and execute SQL operations, you must provide a SQL user account with appropriate privileges in your code. Create one in Databend if needed, and ensure that the SQL user has only the necessary privileges for security.
+
+This tutorial uses a SQL user named 'user1' with password 'abc123' as an example. As the program will write data into Databend, the user needs ALL privileges. For how to manage SQL users and their privileges, see https://databend.rs/doc/reference/sql/ddl/user.
+
+```sql
+CREATE USER user1 IDENTIFIED BY 'abc123';
+GRANT ALL on *.* TO user1;
+```
+
+### Step 2. Write a Node.js Program
+
+In this step, you'll create a simple Node.js program that communicates with Databend. The program will involve tasks such as creating a table, inserting data, and executing data queries.
+
+1. Install the MySQL module and add it as a dependency in your Node.js project.
+
+```text
+npm install --save mysql
+```
+
+2. Copy and paste the following code to a file named `databend.js`:
+
+```js title='databend.js'
+const mysql = require('mysql');
+const con = mysql.createConnection({
+ host: 'localhost',
+ port: 3307,
+ user: 'user1',
+ password: 'abc123',
+});
+
+con.connect((err) => {
+ if (err) throw err;
+ console.log('Connected to Databend Server!');
+
+ var sql = "CREATE DATABASE IF NOT EXISTS book_db";
+ con.query(sql, function (err, result) {
+ if (err) throw err;
+ console.log("Dataabse created");
+ });
+
+ var sql = "USE book_db";
+ con.query(sql, function (err, result) {
+ if (err) throw err;
+ });
+
+
+ var sql = "CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)";
+ con.query(sql, function (err, result) {
+ if (err) throw err;
+ console.log("Table created");
+ });
+
+ var sql = "INSERT INTO books VALUES('mybook', 'author', '2022')";
+ con.query(sql, function (err, result) {
+ if (err) throw err;
+ console.log("1 record inserted");
+ });
+
+ con.query("SELECT * FROM books", function (err, result, fields) {
+ if (err) throw err;
+ console.log(result);
+ });
+
+});
+```
+
+3. Run `nodejs databend.js`:
+
+```text
+Connected to Databend Server!
+Database created
+Table created
+1 record inserted
+[ RowDataPacket { title: 'mybook', author: 'author', date: '2022' } ]
+```
\ No newline at end of file
diff --git a/docs/doc/03-develop/03-java.md b/docs/doc/03-develop/03-java.md
new file mode 100644
index 0000000000000..0e563171ddae7
--- /dev/null
+++ b/docs/doc/03-develop/03-java.md
@@ -0,0 +1,109 @@
+---
+title: Developing with Databend using Java
+sidebar_label: Java
+description:
+ Develop with Databend using Java.
+---
+
+Databend offers a driver (databend-jdbc) written in Java, which facilitates the development of applications using the Java programming language and establishes connectivity with Databend.
+
+For installation instructions, examples, and the source code, see the GitHub [databend-jdbc](https://github.com/databendcloud/databend-jdbc) repo.
+
+In the following tutorial, you'll learn how to utilize the driver `databend-jdbc` to develop your applications. The tutorial will walk you through creating a SQL user in Databend and then writing Java code to create a table, insert data, and perform data queries.
+
+## Tutorial: Developing with Databend using Java
+
+Before you start, make sure you have successfully installed Databend. For how to install Databend, see [How to deploy Databend](/doc/deploy).
+
+### Step 1. Prepare a SQL User Account
+
+To connect your program to Databend and execute SQL operations, you must provide a SQL user account with appropriate privileges in your code. Create one in Databend if needed, and ensure that the SQL user has only the necessary privileges for security.
+
+This tutorial uses a SQL user named 'user1' with password 'abc123' as an example. As the program will write data into Databend, the user needs ALL privileges. For how to manage SQL users and their privileges, see https://databend.rs/doc/reference/sql/ddl/user.
+
+```sql
+CREATE USER user1 IDENTIFIED BY 'abc123';
+GRANT ALL on *.* TO user1;
+```
+
+### Step 2. Write a Java Program
+
+In this step, you'll create a simple Java program that communicates with Databend. The program will involve tasks such as creating a table, inserting data, and executing data queries.
+
+1. Declare a Maven dependency.
+
+```xml
+
+ com.databend
+ databend-jdbc
+ 0.0.4
+
+```
+
+2. Copy and paste the following code to a file named `demo.java`:
+
+```java
+package com.example;
+
+import java.sql.*;
+import java.util.Properties;
+
+public class demo {
+ static final String DB_URL = "jdbc:databend://127.0.0.1:8000";
+
+ public static void main(String[] args) throws Exception {
+ Properties properties = new Properties();
+ properties.setProperty("user", "user1");
+ properties.setProperty("password", "abc123");
+ properties.setProperty("SSL", "false");
+
+ Connection conn = DriverManager.getConnection(DB_URL, properties);
+
+ Statement stmt = conn.createStatement();
+ String create_sql = "CREATE DATABASE IF NOT EXISTS book_db";
+ stmt.execute(create_sql);
+
+ String use_sql = "USE book_db";
+ stmt.execute(use_sql);
+
+ String ct_sql = "CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)";
+ stmt.execute(ct_sql);
+
+ // Insert new book.
+ String title = "mybook";
+ String author = "author";
+ String date = "2022";
+ String add_book = "INSERT INTO books (title, author, date) VALUES ('" + title + "', '" + author + "', '" + date
+ + "')";
+ stmt.execute(add_book);
+
+ // Select book
+ String sql = "SELECT * FROM books";
+ stmt.execute(sql);
+ ResultSet rs = stmt.getResultSet();
+ while (rs.next()) {
+ String col1 = rs.getString("title");
+ String col2 = rs.getString("author");
+ String col3 = rs.getString("date");
+
+ System.out.print("title: " + col1 + ", author: " + col2 + ", date: " + col3);
+ }
+ stmt.execute("drop table books");
+ stmt.execute("drop database book_db");
+ // Close conn
+ conn.close();
+ System.exit(0);
+ }
+}
+```
+
+3. Compile and run the program:
+
+```shell
+$ mvn compile
+$ mvn exec:java -D exec.mainClass="com.example.demo"
+```
+
+```text title='Outputs'
+title: mybook, author: author, date: 2022
+```
diff --git a/docs/doc/20-develop/_category_.json b/docs/doc/03-develop/_category_.json
similarity index 70%
rename from docs/doc/20-develop/_category_.json
rename to docs/doc/03-develop/_category_.json
index 96ec310644389..7af5903757006 100644
--- a/docs/doc/20-develop/_category_.json
+++ b/docs/doc/03-develop/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "Developer Guides",
+ "label": "Develop",
"link": {
"type": "generated-index",
"slug": "/develop"
diff --git a/docs/doc/10-deploy/06-metasrv/15-metasrv-config.md b/docs/doc/10-deploy/06-metasrv/15-metasrv-config.md
index 9d8df14b4aa73..5738368015d5c 100644
--- a/docs/doc/10-deploy/06-metasrv/15-metasrv-config.md
+++ b/docs/doc/10-deploy/06-metasrv/15-metasrv-config.md
@@ -56,7 +56,7 @@ join = ["127.0.0.1:28103", "127.0.0.1:28203"]
## 1. Logging config
-- `log_id` is the path to a directory for storing hourly-rolling debug log.
+- `log_dir` is the path to a directory for storing hourly-rolling debug log.
- `log_level` is the log level. By default, it is `DEBUG`.
## 2. Admin config
diff --git a/docs/doc/10-deploy/07-query/20-query-metrics.md b/docs/doc/10-deploy/07-query/20-query-metrics.md
index 1af78ec313fa8..5fab808afb9d6 100644
--- a/docs/doc/10-deploy/07-query/20-query-metrics.md
+++ b/docs/doc/10-deploy/07-query/20-query-metrics.md
@@ -5,7 +5,7 @@ description:
Databend Query Metrics
---
-A `databend-query` server records metrics in table [system.metrics](../../13-sql-reference/70-system-tables/system-metrics.md).
+A `databend-query` server records metrics in table [system.metrics](../../13-sql-reference/20-system-tables/system-metrics.md).
The [metric_api_address](../07-query/10-query-config.md) to listen on that can be scraped by Prometheus and will return a [prometheus](http://prometheus.io/docs/instrumenting/exposition_formats/) format of metrics.
diff --git a/docs/doc/10-deploy/_category_.json b/docs/doc/10-deploy/_category_.json
index e15737ad9e892..1e22cea138ebf 100644
--- a/docs/doc/10-deploy/_category_.json
+++ b/docs/doc/10-deploy/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "Deploy & Manage Databend",
+ "label": "Deployment",
"link": {
"type": "generated-index",
"slug": "/deploy"
diff --git a/docs/doc/11-integrations/00-api/02-clickhouse-handler.md b/docs/doc/11-integrations/00-api/02-clickhouse-handler.md
index a73a5e3985120..5238e18f61707 100644
--- a/docs/doc/11-integrations/00-api/02-clickhouse-handler.md
+++ b/docs/doc/11-integrations/00-api/02-clickhouse-handler.md
@@ -2,14 +2,14 @@
title: ClickHouse Handler
sidebar_label: ClickHouse Handler
description:
- Databend is ClickHouse wire protocol-compatible.
+ Databend is ClickHouse HTTP API wire protocol-compatible.
---
![image](/img/api/api-handler-clickhouse.png)
## Overview
-Databend is ClickHouse wire protocol-compatible, allow you to connect to Databend server with Clickhouse client, make it easier for users/developers to use Databend.
+Databend is ClickHouse HTTP API wire protocol-compatible, allowing users and developers to easily connect to Databend with ClickHouse HTTP Handler.
## ClickHouse REST API
diff --git a/docs/doc/11-integrations/00-api/03-streaming-load.md b/docs/doc/11-integrations/00-api/03-streaming-load.md
index af5ac5e5ceeb5..a295495d90130 100644
--- a/docs/doc/11-integrations/00-api/03-streaming-load.md
+++ b/docs/doc/11-integrations/00-api/03-streaming-load.md
@@ -17,7 +17,7 @@ To create a request with the Streaming Load API, follow the format below:
curl -H "insert_sql:" -F "upload=@" [-F "upload=@"] -XPUT http://:[password]@:/v1/streaming_load
```
-The parameter `insert_sql` is required and must include an INSERT statement as well as the `FILE_FORMAT` parameter that specifies the file formats. For details about `FILE_FORMAT`, see [Input & Output File Formats](../../13-sql-reference/75-file-format-options.md).
+The parameter `insert_sql` is required and must include an INSERT statement as well as the `FILE_FORMAT` parameter that specifies the file formats. For details about `FILE_FORMAT`, see [Input & Output File Formats](../../13-sql-reference/50-file-format-options.md).
| Parameter | Values | Supported Formats | Examples |
|-------------------------|-------------------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
diff --git a/docs/doc/11-integrations/00-api/_category_.json b/docs/doc/11-integrations/00-api/_category_.json
index 4ffc1be3aebd6..3da7310914cba 100644
--- a/docs/doc/11-integrations/00-api/_category_.json
+++ b/docs/doc/11-integrations/00-api/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "APIs",
+ "label": "API",
"link": {
"type": "generated-index",
"slug": "/reference/api"
diff --git a/docs/doc/11-integrations/10-data-tool/_category_.json b/docs/doc/11-integrations/10-data-tool/_category_.json
index 0ccb3cac911ce..d3438800897b0 100644
--- a/docs/doc/11-integrations/10-data-tool/_category_.json
+++ b/docs/doc/11-integrations/10-data-tool/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "Data Tools",
+ "label": "Ingest",
"link": {
"type": "generated-index",
"slug": "/integrations/data"
diff --git a/docs/doc/11-integrations/20-gui-tool/_category_.json b/docs/doc/11-integrations/20-gui-tool/_category_.json
index b4c17db2f1e5f..e5bd232a0cd01 100644
--- a/docs/doc/11-integrations/20-gui-tool/_category_.json
+++ b/docs/doc/11-integrations/20-gui-tool/_category_.json
@@ -1,5 +1,5 @@
{
- "label": "GUI Tools",
+ "label": "Visualize",
"link": {
"type": "generated-index",
"slug": "/integrations/gui"
diff --git a/docs/doc/12-unload-data/index.md b/docs/doc/12-unload-data/index.md
index ece4a8ef73441..ddf109ab53526 100644
--- a/docs/doc/12-unload-data/index.md
+++ b/docs/doc/12-unload-data/index.md
@@ -7,7 +7,7 @@ Unloading data refers to the process of extracting or transferring data stored i
Databend recommends using the `COPY INTO ` command to export your data to a [Stage](../14-sql-commands/00-ddl/40-stage/index.md) or an external location as a file in one of the supported formats. This command is a convenient and efficient way to transfer data out of the database and into a file for further processing or analysis.
-For more information about the command, see [`COPY INTO `](../14-sql-commands/10-dml/dml-copy-into-location.md). To view the list of supported file formats that can be used to save the exported data, see [Input & Output File Formats](../13-sql-reference/75-file-format-options.md).
+For more information about the command, see [`COPY INTO `](../14-sql-commands/10-dml/dml-copy-into-location.md). To view the list of supported file formats that can be used to save the exported data, see [Input & Output File Formats](../13-sql-reference/50-file-format-options.md).
## Tutorial - Unload to an External Stage
diff --git a/docs/doc/13-sql-reference/10-data-types/10-data-type-numeric-types.md b/docs/doc/13-sql-reference/10-data-types/10-data-type-numeric-types.md
index e25a163179256..983c64e3e15f9 100644
--- a/docs/doc/13-sql-reference/10-data-types/10-data-type-numeric-types.md
+++ b/docs/doc/13-sql-reference/10-data-types/10-data-type-numeric-types.md
@@ -7,12 +7,12 @@ description: Basic Numeric data type.
Basic Integer Numbers data types.
-| Name | Aliases | Storage Size | Min Value | Max Value | Description
-|-----------|--------------| -------------| --------------------------- | ------------------------------- | -------
-| TINYINT | INT8 | 1 byte | -128 | 127 |
-| SMALLINT | INT16 | 2 bytes | -32768 | 32767 |
-| INT | INT32 | 4 bytes | -2147483648 | 2147483647 |
-| BIGINT | INT64 | 8 bytes | -9223372036854775808 | 9223372036854775807 |
+| Name | Aliases | Storage Size | Min Value | Max Value | Description |
+|----------|---------|--------------|----------------------|---------------------|-------------|
+| TINYINT | INT8 | 1 byte | -128 | 127 | |
+| SMALLINT | INT16 | 2 bytes | -32768 | 32767 | |
+| INT | INT32 | 4 bytes | -2147483648 | 2147483647 | |
+| BIGINT | INT64 | 8 bytes | -9223372036854775808 | 9223372036854775807 | |
:::tip
If you want unsigned integer, please use `UNSIGNED` constraint, this is compatible with MySQL, for example:
@@ -26,10 +26,10 @@ CREATE TABLE test_numeric(tiny TINYINT, tiny_unsigned TINYINT UNSIGNED)
Basic Float32/Float64 data types.
-| Name | Aliases | Storage Size | Min Value | Max Value | Description
-|-----------|--------------| -------------| --------------------------- | ------------------------------- | -------
-| FLOAT | | 4 bytes | -3.40282347e+38 | 3.40282347e+38 |
-| DOUBLE | | 8 bytes | -1.7976931348623157E+308 | 1.7976931348623157E+308 |
+| Name | Aliases | Storage Size | Min Value | Max Value | Description |
+|--------|---------|--------------|--------------------------|-------------------------|-------------|
+| FLOAT | | 4 bytes | -3.40282347e+38 | 3.40282347e+38 | |
+| DOUBLE | | 8 bytes | -1.7976931348623157E+308 | 1.7976931348623157E+308 | |
## Functions
diff --git a/docs/doc/13-sql-reference/10-data-types/43-data-type-decimal-types.md b/docs/doc/13-sql-reference/10-data-types/11-data-type-decimal-types.md
similarity index 58%
rename from docs/doc/13-sql-reference/10-data-types/43-data-type-decimal-types.md
rename to docs/doc/13-sql-reference/10-data-types/11-data-type-decimal-types.md
index c93ac416c2f4e..486a32fbe7175 100644
--- a/docs/doc/13-sql-reference/10-data-types/43-data-type-decimal-types.md
+++ b/docs/doc/13-sql-reference/10-data-types/11-data-type-decimal-types.md
@@ -14,11 +14,29 @@ We can use `DECIMAL(P, S)` to indicate decimal types.
If `P` is less than 38, the physical datatype of decimal is `Decimal128`, otherwise it's `Decimal256`.
+For a DECIMAL(P, S) data type:
+* The minimum value is `-10^P + 1` divided by `10^S`.
+* The maximum value is `10^P - 1` divided by `10^S`.
+
+If you have a `DECIMAL(10, 2)` , you can store values with up to `10 digits`, with `2 digits` to the right of the decimal point. The minimum value is `-9999999.99`, and the maximum value is `9999999.99`.
+
## Example
```sql
-select 3::Decimal(19, 1); -- 3.0
+-- Create a table with decimal data type.
+create table decimal(value decimal(36, 18));
+
+-- Insert two values.
+insert into decimal values(0.152587668674722117), (0.017820781941443176);
+
+select * from decimal;
++----------------------+
+| value |
++----------------------+
+| 0.152587668674722117 |
+| 0.017820781941443176 |
++----------------------+
```
## Precision Inference
@@ -27,16 +45,21 @@ DECIMAL has a set of complex rules for precision inference. Different rules will
### Arithmetic Operations
-- Addition/Subtraction: DECIMAL(a, b) + DECIMAL(x, y) -> DECIMAL(max(a - b, x - y) + max(b, y) + 1, max(b, y)), which means both integer and decimal parts use the larger value of the two operands.
+- Addition/Subtraction: `DECIMAL(a, b) + DECIMAL(x, y) -> DECIMAL(max(a - b, x - y) + max(b, y) + 1, max(b, y))`, which means both integer and decimal parts use the larger value of the two operands.
+
+- Multiplication: `DECIMAL(a, b) * DECIMAL(x, y) -> DECIMAL(a + x, b + y)`.
+
+- Division: `DECIMAL(a, b) / DECIMAL(x, y) -> DECIMAL(a + y, b)`.
-- Multiplication: DECIMAL(a, b) * DECIMAL(x, y) -> DECIMAL(a + x, b + y).
+### Comparison Operations
-- Division: DECIMAL(a, b) / DECIMAL(x, y) -> DECIMAL(a + y, b).
+- Decimal can be compared with other numeric types.
+- Decimal can be compared with other decimal types.
### Aggregate Operations
-- SUM: SUM(DECIMAL(a, b)) -> DECIMAL(MAX, b)
-- AVG: AVG(DECIMAL(a, b)) -> DECIMAL(MAX, max(b, 4))
+- SUM: `SUM(DECIMAL(a, b)) -> DECIMAL(MAX, b)`
+- AVG: `AVG(DECIMAL(a, b)) -> DECIMAL(MAX, max(b, 4))`
where `MAX` is 38 for decimal128 and 76 for decimal256.
diff --git a/docs/doc/13-sql-reference/10-data-types/index.md b/docs/doc/13-sql-reference/10-data-types/index.md
index ab1d001cec92b..beac260821f40 100644
--- a/docs/doc/13-sql-reference/10-data-types/index.md
+++ b/docs/doc/13-sql-reference/10-data-types/index.md
@@ -7,36 +7,34 @@ slug: ./
Databend supports SQL data types in several categories:
* [Boolean Data Types](00-data-type-logical-types.md)
* [Numeric Data Types](10-data-type-numeric-types.md)
+* [Decimal Data Types](11-data-type-decimal-types.md)
* [Date & Time Data Types](20-data-type-time-date-types.md)
* [String Data Types](30-data-type-string-types.md)
-* [Decimal Data Types](43-data-type-decimal-types.md)
* [Array(T) Data Types](40-data-type-array-types.md)
* [Tuple Data Types](41-data-type-tuple-types.md)
* [Semi-structured Data Types](42-data-type-semi-structured-types.md)
## General-Purpose Data Types
-| Name | Aliases | Storage Size | Min Value | Max Value | Description
-|-----------|--------------| -------------| --------------------------- | -------------------------------| -------
-| BOOLEAN | BOOL | 1 byte | | | Logical boolean (true/false)
-| TINYINT | INT8 | 1 byte | -128 | 127 |
-| SMALLINT | INT16 | 2 bytes | -32768 | 32767 |
-| INT | INT32 | 4 bytes | -2147483648 | 2147483647 |
-| BIGINT | INT64 | 8 bytes | -9223372036854775808 | 9223372036854775807 |
-| FLOAT | | 4 bytes | -3.40282347e+38 | 3.40282347e+38 |
-| DOUBLE | | 8 bytes | -1.7976931348623157E+308 | 1.7976931348623157E+308 |
-| DATE | | 4 bytes | 1000-01-01 | 9999-12-31 | YYYY-MM-DD
-| TIMESTAMP | | 8 bytes | 0001-01-01 00:00:00 | 9999-12-31 23:59:59.999999 UTC | YYYY-MM-DD hh:mm:ss[.fraction], up to microseconds (6 digits) precision
-| VARCHAR | STRING | variable | | |
-
+| Name | Aliases | Storage Size | Min Value | Max Value | Description |
+|---------------|---------|--------------|--------------------------|--------------------------------|-------------------------------------------------------------------------|
+| **BOOLEAN** | BOOL | 1 byte | | | Logical boolean (true/false) |
+| **TINYINT** | INT8 | 1 byte | -128 | 127 | |
+| **SMALLINT** | INT16 | 2 bytes | -32768 | 32767 | |
+| **INT** | INT32 | 4 bytes | -2147483648 | 2147483647 | |
+| **BIGINT** | INT64 | 8 bytes | -9223372036854775808 | 9223372036854775807 | |
+| **FLOAT** | | 4 bytes | -3.40282347e+38 | 3.40282347e+38 | |
+| **DOUBLE** | | 8 bytes | -1.7976931348623157E+308 | 1.7976931348623157E+308 | |
+| **DECIMAL** | | 16/32 bytes | -10^P / 10^S | 10^P / 10^S | |
+| **DATE** | | 4 bytes | 1000-01-01 | 9999-12-31 | YYYY-MM-DD |
+| **TIMESTAMP** | | 8 bytes | 0001-01-01 00:00:00 | 9999-12-31 23:59:59.999999 UTC | YYYY-MM-DD hh:mm:ss[.fraction], up to microseconds (6 digits) precision |
+| **VARCHAR** | STRING | variable | | | |
+| **ARRAY** | | | | | [1,2,3] |
+| **TUPLE** | | | | | ('2023-02-14 08:00:00','Valentine's Day') |
## Semi-structured Data Types
-Databend supports three Semi-structured types: ARRAY, OBJECT and VARIANT.
-
-| Name | Aliases | Build From Values | Description
-|---------|--------------|-------------------------|----------------
-| ARRAY | | [1,2,3] | Zero-based indexed list, each value can have difference data type.
-| TUPLE | | ('2023-02-14 08:00:00','Valentine's Day') | Collection of ordered,immmutable, which requires the type of each element to be declared before being used.
-| VARIANT | JSON | [1,{"a":1,"b":{"c":2}}] | Collection of elements of different data types., including ARRAY and OBJECT.
+| Name | Aliases | Build From Values | Description |
+|-------------|---------|-------------------------------------------|-------------------------------------------------------------------------------------------------------------|
+| **VARIANT** | JSON | [1,{"a":1,"b":{"c":2}}] | Collection of elements of different data types., including ARRAY and OBJECT. |
diff --git a/docs/doc/13-sql-reference/70-system-tables/_category_.json b/docs/doc/13-sql-reference/20-system-tables/_category_.json
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/_category_.json
rename to docs/doc/13-sql-reference/20-system-tables/_category_.json
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-build-options.md b/docs/doc/13-sql-reference/20-system-tables/system-build-options.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-build-options.md
rename to docs/doc/13-sql-reference/20-system-tables/system-build-options.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-clusters.md b/docs/doc/13-sql-reference/20-system-tables/system-clusters.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-clusters.md
rename to docs/doc/13-sql-reference/20-system-tables/system-clusters.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-columns.md b/docs/doc/13-sql-reference/20-system-tables/system-columns.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-columns.md
rename to docs/doc/13-sql-reference/20-system-tables/system-columns.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-configs.md b/docs/doc/13-sql-reference/20-system-tables/system-configs.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-configs.md
rename to docs/doc/13-sql-reference/20-system-tables/system-configs.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-contributors.md b/docs/doc/13-sql-reference/20-system-tables/system-contributors.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-contributors.md
rename to docs/doc/13-sql-reference/20-system-tables/system-contributors.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-credits.md b/docs/doc/13-sql-reference/20-system-tables/system-credits.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-credits.md
rename to docs/doc/13-sql-reference/20-system-tables/system-credits.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-functions.md b/docs/doc/13-sql-reference/20-system-tables/system-functions.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-functions.md
rename to docs/doc/13-sql-reference/20-system-tables/system-functions.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-metrics.md b/docs/doc/13-sql-reference/20-system-tables/system-metrics.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-metrics.md
rename to docs/doc/13-sql-reference/20-system-tables/system-metrics.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-numbers.md b/docs/doc/13-sql-reference/20-system-tables/system-numbers.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-numbers.md
rename to docs/doc/13-sql-reference/20-system-tables/system-numbers.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-query-log.md b/docs/doc/13-sql-reference/20-system-tables/system-query-log.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-query-log.md
rename to docs/doc/13-sql-reference/20-system-tables/system-query-log.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-settings.md b/docs/doc/13-sql-reference/20-system-tables/system-settings.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-settings.md
rename to docs/doc/13-sql-reference/20-system-tables/system-settings.md
diff --git a/docs/doc/13-sql-reference/70-system-tables/system-tracing.md b/docs/doc/13-sql-reference/20-system-tables/system-tracing.md
similarity index 100%
rename from docs/doc/13-sql-reference/70-system-tables/system-tracing.md
rename to docs/doc/13-sql-reference/20-system-tables/system-tracing.md
diff --git a/docs/doc/16-table-engines/00-fuse.md b/docs/doc/13-sql-reference/30-table-engines/00-fuse.md
similarity index 97%
rename from docs/doc/16-table-engines/00-fuse.md
rename to docs/doc/13-sql-reference/30-table-engines/00-fuse.md
index c1eba5f82a7b8..f2aa0cc223d45 100644
--- a/docs/doc/16-table-engines/00-fuse.md
+++ b/docs/doc/13-sql-reference/30-table-engines/00-fuse.md
@@ -16,7 +16,7 @@ CREATE TABLE table_name (
) [ENGINE = Fuse] [CLUSTER BY( [, , ...] )] [options];
```
-Read more about the create table statement in [ddl-create-table](../14-sql-commands/00-ddl/20-table/10-ddl-create-table.md)
+Read more about the create table statement in [ddl-create-table](../../14-sql-commands/00-ddl/20-table/10-ddl-create-table.md)
### Default engine
diff --git a/docs/doc/16-table-engines/01-memory.md b/docs/doc/13-sql-reference/30-table-engines/01-memory.md
similarity index 100%
rename from docs/doc/16-table-engines/01-memory.md
rename to docs/doc/13-sql-reference/30-table-engines/01-memory.md
diff --git a/docs/doc/16-table-engines/_category_.json b/docs/doc/13-sql-reference/30-table-engines/_category_.json
similarity index 100%
rename from docs/doc/16-table-engines/_category_.json
rename to docs/doc/13-sql-reference/30-table-engines/_category_.json
diff --git a/docs/doc/13-sql-reference/20-sql-identifiers.md b/docs/doc/13-sql-reference/40-sql-identifiers.md
similarity index 96%
rename from docs/doc/13-sql-reference/20-sql-identifiers.md
rename to docs/doc/13-sql-reference/40-sql-identifiers.md
index c71e6aa0b5ae7..aea13d27c39af 100644
--- a/docs/doc/13-sql-reference/20-sql-identifiers.md
+++ b/docs/doc/13-sql-reference/40-sql-identifiers.md
@@ -78,7 +78,7 @@ By default, Databend applies the following rules for storing identifiers (at cre
* When an identifier is double-quoted, it is stored and resolved exactly as entered, including case.
-If want to preserve the case of characters when use `unquoted identifier`, need set [unquoted_ident_case_sensitive](70-system-tables/system-settings.md) = 1.
+If want to preserve the case of characters when use `unquoted identifier`, need set [unquoted_ident_case_sensitive](20-system-tables/system-settings.md) = 1.
Examples:
@@ -106,7 +106,7 @@ databend :) desc tt;
```
-If do not want to preserve the case of characters when use `double identifier`, need set [quoted_ident_case_sensitive](70-system-tables/system-settings.md) = 0.
+If do not want to preserve the case of characters when use `double identifier`, need set [quoted_ident_case_sensitive](20-system-tables/system-settings.md) = 0.
Examples:
diff --git a/docs/doc/13-sql-reference/75-file-format-options.md b/docs/doc/13-sql-reference/50-file-format-options.md
similarity index 100%
rename from docs/doc/13-sql-reference/75-file-format-options.md
rename to docs/doc/13-sql-reference/50-file-format-options.md
diff --git a/docs/doc/14-sql-commands/00-ddl/100-file-format/01-ddl-create-file-format.md b/docs/doc/14-sql-commands/00-ddl/100-file-format/01-ddl-create-file-format.md
index a7641a1ca987f..30cad0db02dc4 100644
--- a/docs/doc/14-sql-commands/00-ddl/100-file-format/01-ddl-create-file-format.md
+++ b/docs/doc/14-sql-commands/00-ddl/100-file-format/01-ddl-create-file-format.md
@@ -10,7 +10,7 @@ Creates a named file format.
CREATE FILE FORMAT [ IF NOT EXISTS ] FileFormatOptions
```
-For details about `FileFormatOptions`, see [Input & Output File Formats](../../../13-sql-reference/75-file-format-options.md).
+For details about `FileFormatOptions`, see [Input & Output File Formats](../../../13-sql-reference/50-file-format-options.md).
## Examples
diff --git a/docs/doc/14-sql-commands/00-ddl/40-stage/01-ddl-create-stage.md b/docs/doc/14-sql-commands/00-ddl/40-stage/01-ddl-create-stage.md
index 6ca11214967c7..1b457b45e063f 100644
--- a/docs/doc/14-sql-commands/00-ddl/40-stage/01-ddl-create-stage.md
+++ b/docs/doc/14-sql-commands/00-ddl/40-stage/01-ddl-create-stage.md
@@ -120,7 +120,7 @@ externalLocation ::=
### formatTypeOptions
-For details about `FILE_FORMAT`, see [Input & Output File Formats](../../../13-sql-reference/75-file-format-options.md).
+For details about `FILE_FORMAT`, see [Input & Output File Formats](../../../13-sql-reference/50-file-format-options.md).
### copyOptions
```
@@ -146,7 +146,7 @@ CREATE STAGE my_internal_stage;
### External Stages
```sql
-CREATE STAGE my_s3_stage url='s3://load/files/' connection=(aws_key_id='1a2b3c' aws_secret_key='4x5y6z');
+CREATE STAGE my_s3_stage URL='s3://load/files/' CONNECTION = (ACCESS_KEY_ID = '' SECRET_ACCESS_KEY = '');
```
```sql
@@ -156,4 +156,4 @@ DESC STAGE my_s3_stage;
+-------------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------+---------+
| my_s3_stage | External | StageParams { storage: S3(StageS3Storage { bucket: "load", path: "/files/", credentials_aws_key_id: "", credentials_aws_secret_key: "", encryption_master_key: "" }) } | CopyOptions { on_error: None, size_limit: 0 } | FileFormatOptions { format: Csv, skip_header: 0, field_delimiter: ",", record_delimiter: "\n", compression: None } | |
+-------------+------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------+--------------------------------------------------------------------------------------------------------------------+---------+
-```
\ No newline at end of file
+```
diff --git a/docs/doc/14-sql-commands/10-dml/dml-copy-into-location.md b/docs/doc/14-sql-commands/10-dml/dml-copy-into-location.md
index 76420945a1827..56b77deb1670f 100644
--- a/docs/doc/14-sql-commands/10-dml/dml-copy-into-location.md
+++ b/docs/doc/14-sql-commands/10-dml/dml-copy-into-location.md
@@ -56,7 +56,7 @@ externalLocation (for Amazon S3) ::=
### FILE_FORMAT
-See [Input & Output File Formats](../../13-sql-reference/75-file-format-options.md).
+See [Input & Output File Formats](../../13-sql-reference/50-file-format-options.md).
### copyOptions
```
diff --git a/docs/doc/14-sql-commands/10-dml/dml-copy-into-table.md b/docs/doc/14-sql-commands/10-dml/dml-copy-into-table.md
index 9e6ee6ee42e5c..a01d987060b61 100644
--- a/docs/doc/14-sql-commands/10-dml/dml-copy-into-table.md
+++ b/docs/doc/14-sql-commands/10-dml/dml-copy-into-table.md
@@ -186,7 +186,7 @@ A [PCRE2](https://www.pcre.org/current/doc/html/)-based regular expression patte
### FILE_FORMAT
-See [Input & Output File Formats](../../13-sql-reference/75-file-format-options.md).
+See [Input & Output File Formats](../../13-sql-reference/50-file-format-options.md).
### copyOptions
diff --git a/docs/doc/14-sql-commands/40-show/show-metrics.md b/docs/doc/14-sql-commands/40-show/show-metrics.md
index 05ede3a8385bb..93e9c253d7af8 100644
--- a/docs/doc/14-sql-commands/40-show/show-metrics.md
+++ b/docs/doc/14-sql-commands/40-show/show-metrics.md
@@ -2,7 +2,7 @@
title: SHOW METRICS
---
-Shows the list of [system metrics](../../13-sql-reference/70-system-tables/system-metrics.md).
+Shows the list of [system metrics](../../13-sql-reference/20-system-tables/system-metrics.md).
## Syntax
diff --git a/docs/doc/14-sql-commands/40-show/show-settings.md b/docs/doc/14-sql-commands/40-show/show-settings.md
index 4421a7cc668ff..ce3772d75539a 100644
--- a/docs/doc/14-sql-commands/40-show/show-settings.md
+++ b/docs/doc/14-sql-commands/40-show/show-settings.md
@@ -2,7 +2,7 @@
title: SHOW SETTINGS
---
-Shows the databend's [system settings](../../13-sql-reference/70-system-tables/system-settings.md).
+Shows the databend's [system settings](../../13-sql-reference/20-system-tables/system-settings.md).
You can change it by set command, like `set max_threads = 1`.
diff --git a/docs/doc/15-sql-functions/112-table-functions/stage_table_function.md b/docs/doc/15-sql-functions/112-table-functions/stage_table_function.md
index 8464edf4fd03d..d390cabe0b496 100644
--- a/docs/doc/15-sql-functions/112-table-functions/stage_table_function.md
+++ b/docs/doc/15-sql-functions/112-table-functions/stage_table_function.md
@@ -32,7 +32,7 @@ The function parameters are as follows:
`` should be one of the following:
-1. A built-in file format (see [Input & Output File Formats](../../13-sql-reference/75-file-format-options.md).
+1. A built-in file format (see [Input & Output File Formats](../../13-sql-reference/50-file-format-options.md).
2. A named file format created by [CREATE FILE FORMAT](../../14-sql-commands/00-ddl/100-file-format/01-ddl-create-file-format.md).
If not specified for named stages, the format of the stage should be used.
diff --git a/docs/doc/15-sql-functions/130-geo-functions/_category_.json b/docs/doc/15-sql-functions/130-geo-functions/_category_.json
index 619196e8dd15e..d61abd3523d33 100644
--- a/docs/doc/15-sql-functions/130-geo-functions/_category_.json
+++ b/docs/doc/15-sql-functions/130-geo-functions/_category_.json
@@ -1,7 +1,3 @@
{
- "label": "Geography Functions",
- "link": {
- "type": "generated-index",
- "slug": "/reference/functions/geo-functions"
- }
+ "label": "Geography Functions"
}
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/130-geo-functions/geo_to_h3.md b/docs/doc/15-sql-functions/130-geo-functions/geo_to_h3.md
deleted file mode 100644
index 4203351f9f96c..0000000000000
--- a/docs/doc/15-sql-functions/130-geo-functions/geo_to_h3.md
+++ /dev/null
@@ -1,38 +0,0 @@
----
-title: GEO_TO_H3
----
-
-Returns the [H3](https://eng.uber.com/h3/) index of the hexagon cell where the given location resides.
-
-## Syntax
-
-```sql
-GEO_TO_H3(lon, lat, res)
-```
-
-## Arguments
-
-| Argument | Type | Description |
-|------------|---------|-----------------------------------------------------------------------------------------------------------|
-| lon | Float64 | Specifies the location's longitude, for example, `37.79506683`. |
-| lat | Float64 | Specifies the location's latitude, for example, `55.71290588`. |
-| res | UInt8 | Sets an [H3 resolution](https://h3geo.org/docs/core-library/restable) ranging from 0 to 15.|
-
-## Return Type
-
-UInt64.
-
-:::note
-Returning 0 means an error occurred.
-:::
-
-## Examples
-
-```sql
-SELECT GEO_TO_H3(37.79506683, 55.71290588, 15) AS h3Index;
-+-------------------------------+
-| h3Index |
-+-------------------------------+
-| 644325524701193974 |
-+-------------------------------+
-```
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/130-geo-functions/geohash_decode.md b/docs/doc/15-sql-functions/130-geo-functions/geohash_decode.md
deleted file mode 100644
index 3e0fbdef254f0..0000000000000
--- a/docs/doc/15-sql-functions/130-geo-functions/geohash_decode.md
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: GEOHASH_DECODE
----
-
-Converts a [Geohash](https://en.wikipedia.org/wiki/Geohash)-encoded string into latitude/longitude coordinates.
-
-See also: [GEOHASH_ENCODE](geohash_encode.md)
-
-## Syntax
-
-```sql
-GEOHASH_DECODE('')
-```
-
-## Return Type
-
-Returns a latitude(Float64) and longitude(Float64) pair.
-
-## Examples
-
-```sql
-SELECT GEOHASH_DECODE('ezs42')
-
-----
-(-5.60302734375,42.60498046875)
-```
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/130-geo-functions/geohash_encode.md b/docs/doc/15-sql-functions/130-geo-functions/geohash_encode.md
deleted file mode 100644
index d072fe39913d1..0000000000000
--- a/docs/doc/15-sql-functions/130-geo-functions/geohash_encode.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: GEOHASH_ENCODE
----
-
-Converts a pair of latitude and longitude coordinates into a [Geohash](https://en.wikipedia.org/wiki/Geohash)-encoded string.
-
-See also: [GEOHASH_DECODE](geohash_decode.md)
-
-## Syntax
-
-```sql
-GEOHASH_ENCODE(lon, lat)
-```
-## Arguments
-
-| Argument | Type | Description |
-|------------|---------|-----------------------------------------------------------------------------------------------------------|
-| lon | Float64 | Specifies the location's longitude, for example, `37.79506683`. |
-| lat | Float64 | Specifies the location's latitude, for example, `55.71290588`. |
-
-## Return Type
-
-Returns a [Geohash](https://en.wikipedia.org/wiki/Geohash)-encoded string.
-
-## Examples
-
-```sql
-SELECT GEOHASH_ENCODE(-5.60302734375, 42.593994140625)
-
-----
-ezs42d000000
-```
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/130-geo-functions/index.md b/docs/doc/15-sql-functions/130-geo-functions/index.md
new file mode 100644
index 0000000000000..18978dc77912e
--- /dev/null
+++ b/docs/doc/15-sql-functions/130-geo-functions/index.md
@@ -0,0 +1,17 @@
+---
+title: 'Geography Functions'
+---
+
+| Function | Description | Example | Result |
+|---------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------|---------------------------------|
+| **GEO_TO_H3(lon, lat, res)** | Returns the [H3](https://eng.uber.com/h3/) index of the hexagon cell where the given location resides. | **GEO_TO_H3(37.79506683, 55.71290588, 15)** | 644325524701193974 |
+| **GEOHASH_DECODE('')** | Converts a [Geohash](https://en.wikipedia.org/wiki/Geohash)-encoded string into latitude/longitude coordinates. | **GEOHASH_DECODE('ezs42')** | (-5.60302734375,42.60498046875) |
+| **GEOHASH_ENCODE(lon, lat)** | Converts a pair of latitude and longitude coordinates into a [Geohash](https://en.wikipedia.org/wiki/Geohash)-encoded string. | **GEOHASH_ENCODE(-5.60302734375, 42.593994140625)** | ezs42d000000 |
+| **POINT_IN_POLYGON((x,y), [(a,b), (c,d), (e,f) ... ])** | Calculates whether a given point falls within the polygon formed by joining multiple points. | **POINT_IN_POLYGON((3., 3.), [(6, 0), (8, 4), (5, 8), (0, 2)])** | 1 |
+
+:::note
+
+- `GEO_TO_H3(lon, lat, res)` returning 0 means an error occurred.
+- `POINT_IN_POLYGON((x,y), [(a,b), (c,d), (e,f) ... ])` A polygon is a closed shape connected by coordinate pairs in the order they appear. Changing the order of coordinate pairs can result in a different shape.
+
+:::
diff --git a/docs/doc/15-sql-functions/130-geo-functions/point_in_polygon.md b/docs/doc/15-sql-functions/130-geo-functions/point_in_polygon.md
deleted file mode 100644
index 35d698bc78b66..0000000000000
--- a/docs/doc/15-sql-functions/130-geo-functions/point_in_polygon.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: POINT_IN_POLYGON
----
-
-Calculates whether a given point falls within the polygon formed by joining multiple points.
-
-## Syntax
-
-```sql
-POINT_IN_POLYGON((x,y), [(a,b), (c,d), (e,f) ... ])
-```
-
-## Arguments
-
-| Argument | Type | Description |
-|-------------------------|-------------------|---------------------------------------------------------------------|
-| (x,y) | (Float64,Float64) | Coordinates of the given point. |
-| (a,b), (c,d), (e,f) ... | VARIANT | An ordered list of coordinate pairs defining the shape of a polygon.|
-
-:::note
-A polygon is a closed shape connected by coordinate pairs in the order they appear. Changing the order of coordinate pairs can result in a different shape.
-:::
-
-## Return Type
-
-Returns 1 if the given point falls within the formed polygon; otherwise, returns 0.
-
-## Examples
-
-```sql
-SELECT POINT_IN_POLYGON((3., 3.), [(6, 0), (8, 4), (5, 8), (0, 2)])
-
-----
-1
-```
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/60-conversion-functions/_category_.json b/docs/doc/15-sql-functions/60-conversion-functions/_category_.json
index 1e2dc5a064e4e..d638b6eacfa54 100644
--- a/docs/doc/15-sql-functions/60-conversion-functions/_category_.json
+++ b/docs/doc/15-sql-functions/60-conversion-functions/_category_.json
@@ -1,7 +1,3 @@
{
- "label": "Conversion Functions",
- "link": {
- "type": "generated-index",
- "slug": "/reference/functions/conversion-functions"
- }
+ "label": "Conversion Functions"
}
\ No newline at end of file
diff --git a/docs/doc/15-sql-functions/60-conversion-functions/cast.md b/docs/doc/15-sql-functions/60-conversion-functions/cast.md
deleted file mode 100644
index af3aad8a83df4..0000000000000
--- a/docs/doc/15-sql-functions/60-conversion-functions/cast.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: CAST
----
-
-Convert a value from one data type to another data type.
-
-## Syntax
-
-```sql
-CAST( AS )
-::
-```
-
-## Arguments
-
-| Arguments | Description |
-| ----------- | ----------- |
-| `` | A value to convert. |
-| `` | The target data type |
-
-:::tip
-
-[Databend Data Types](../../13-sql-reference/10-data-types/index.md)
-
-:::
-
-## Return Type
-
-Converted value.
-
-## Examples
-
-```sql
-SELECT CAST(1 AS VARCHAR);
-+-------------------+
-| cast(1 as String) |
-+-------------------+
-| 1 |
-+-------------------+
-
-SELECT 1::VARCHAR;
-+-----------+
-| 1::String |
-+-----------+
-| 1 |
-+-----------+
-
-SELECT CAST(1 AS BIGINT UNSIGNED);
-+-------------------+
-| cast(1 as UInt64) |
-+-------------------+
-| 1 |
-+-------------------+
-
-SELECT typeof(CAST(1 AS BIGINT UNSIGNED));
-+-------------------------------+
-| typeof(cast(1 as UInt64)) |
-+-------------------------------+
-| UInt64 |
-+-------------------------------+
-```
diff --git a/docs/doc/15-sql-functions/60-conversion-functions/index.md b/docs/doc/15-sql-functions/60-conversion-functions/index.md
new file mode 100644
index 0000000000000..9168435e24849
--- /dev/null
+++ b/docs/doc/15-sql-functions/60-conversion-functions/index.md
@@ -0,0 +1,35 @@
+---
+title: 'Conversion Functions'
+---
+
+| Function | Description | Example | Result |
+|-----------------------------------|----------------------------------------------------------------------------------------|------------------------------------|----------------------------|
+| **CAST( expr AS data_type )** | Convert a value from one data type to another data type | **CAST(1 AS VARCHAR)** | 1 |
+| **expr::data_type** | alias for CAST | **1::VARCHAR** | 1 |
+| **TRY_CAST( expr AS data_type )** | Convert a value from one data type to another data type. If error happens, return NULL | **TRY_CAST(1 AS VARCHAR)** | 1 |
+| **TO_BOOLEAN( expr )** | Convert a value to BOOLEAN data type | **TO_BOOLEAN('true')** | 1 |
+| **TO_DATE( expr )** | Convert a value to DATE data type | **TO_DATE(19109)** | 2022-04-27 |
+| **TO_DATETIME( expr )** | Convert a value to DATETIME data type | **TO_DATETIME(1651036648)** | 2022-04-27 05:17:28.000000 |
+| **TO_TIMESTAMP( expr )** | alias for TO_DATETIME | **TO_TIMESTAMP(1651036648123456)** | 2022-04-27 05:17:28.123456 |
+| **TO_FLOAT32( expr )** | Convert a value to FLOAT32 data type | **TO_FLOAT32('1.2')** | 1.2 |
+| **TO_FLOAT64( expr )** | Convert a value to FLOAT64 data type | **TO_FLOAT64('1.2')** | 1.2 |
+| **TO_INT8( expr )** | Convert a value to INT8 data type | **TO_INT8('123')** | 123 |
+| **TO_INT16( expr )** | Convert a value to INT16 data type | **TO_INT16('123')** | 123 |
+| **TO_INT32( expr )** | Convert a value to INT32 data type | **TO_INT32('123')** | 123 |
+| **TO_INT64( expr )** | Convert a value to INT64 data type | **TO_INT64('123')** | 123 |
+| **TO_UINT8( expr )** | Convert a value to UINT8 data type | **TO_UINT8('123')** | 123 |
+| **TO_UINT16( expr )** | Convert a value to UINT16 data type | **TO_UINT16('123')** | 123 |
+| **TO_UINT32( expr )** | Convert a value to UINT32 data type | **TO_UINT32('123')** | 123 |
+| **TO_UINT64( expr )** | Convert a value to UINT64 data type | **TO_UINT64('123')** | 123 |
+| **TO_STRING( expr )** | Convert a value to STRING data type | **TO_STRING(10)** | 10 |
+
+
+:::note
+
+`TO_DATETIME( expr )` and `TO_TIMESTAMP( expr )` uses the following rules to automatically determine the unit of time:
+
+- If the value is less than 31536000000, it is treated as a number of seconds,
+- If the value is greater than or equal to 31536000000 and less than 31536000000000, it is treated as milliseconds.
+- If the value is greater than or equal to 31536000000000, it is treated as microseconds.
+
+:::
diff --git a/docs/doc/15-sql-functions/60-conversion-functions/try_cast.md b/docs/doc/15-sql-functions/60-conversion-functions/try_cast.md
deleted file mode 100644
index b9858e9a60405..0000000000000
--- a/docs/doc/15-sql-functions/60-conversion-functions/try_cast.md
+++ /dev/null
@@ -1,47 +0,0 @@
----
-title: TRY_CAST
----
-
-Convert a value from one data type to another data type. If error happens, return NULL.
-
-## Syntax
-
-```sql
-TRY_CAST(x AS t)
-```
-
-## Arguments
-
-| Arguments | Description |
-| ----------- | ----------- |
-| x | A value to convert. |
-| t | The target data type. |
-
-## Return Type
-
-Nullable datatype of the target data type
-
-## Examples
-
-```sql
-SELECT try_cast(1 AS VARCHAR);
-+-----------------------+
-| try_cast(1 as String) |
-+-----------------------+
-| 1 |
-+-----------------------+
-
-SELECT try_cast('abc' AS INT UNSIGNED);
-+---------------------------+
-| try_cast('abc' as UInt32) |
-+---------------------------+
-| NULL |
-+---------------------------+
-
-SELECT typeof(try_cast('abc' AS INT UNSIGNED));
-+-----------------------------------+
-| typeof(try_cast('abc' as uint32)) |
-+-----------------------------------+
-| INT UNSIGNED NULL |
-+-----------------------------------+
-```
diff --git a/docs/doc/15-sql-functions/60-conversion-functions/type_conversion.md b/docs/doc/15-sql-functions/60-conversion-functions/type_conversion.md
deleted file mode 100644
index 0e1399cf54555..0000000000000
--- a/docs/doc/15-sql-functions/60-conversion-functions/type_conversion.md
+++ /dev/null
@@ -1,106 +0,0 @@
----
-title: Type Conversion
----
-
-Type conversion to target type.
-
-## Syntax
-
-```sql
-TO_BOOLEAN( )
-TO_DATE( )
-TO_DATETIME( )
-TO_TIMESTAMP( )
-TO_FLOAT32( )
-TO_FLOAT64( )
-TO_INT8( )
-TO_INT16( )
-TO_INT32( )
-TO_INT64( )
-TO_NULL( )
-TO_STRING( )
-TO_UINT8( )
-TO_UINT16( )
-TO_UINT32( )
-TO_UINT64( )
-```
-
-> `TO_DATETIME( )` and `TO_TIMESTAMP( )` uses the following rules to automatically determine the unit of time:
->
-> - If the value is less than 31536000000, it is treated as a number of seconds,
-> - If the value is greater than or equal to 31536000000 and less than 31536000000000, it is treated as milliseconds.
-> - If the value is greater than or equal to 31536000000000, it is treated as microseconds.
-
-## Examples
-
-```sql
-SELECT to_boolean('true');
-+--------------------+
-| to_boolean('true') |
-+--------------------+
-| 1 |
-+--------------------+
-
-SELECT to_date(19109);
-+----------------+
-| to_date(19109) |
-+----------------+
-| 2022-04-27 |
-+----------------+
-
-SELECT to_datetime(1651036648);
-+----------------------------+
-| to_datetime(1651036648) |
-+----------------------------+
-| 2022-04-27 05:17:28.000000 |
-+----------------------------+
-
-SELECT to_datetime(1651036648123);
-+----------------------------+
-| to_datetime(1651036648123) |
-+----------------------------+
-| 2022-04-27 05:17:28.123000 |
-+----------------------------+
-
-SELECT to_timstamp(1651036648123456);
-+--------------------------------+
-| to_timstamp(1651036648123456) |
-+--------------------------------+
-| 2022-04-27 05:17:28.123456 |
-+--------------------------------+
-
-SELECT to_float32('1.2');
-+--------------------+
-| to_float32('1.2') |
-+--------------------+
-| 1.2000000476837158 |
-+--------------------+
-
-SELECT to_float64('1.2');
-+-------------------+
-| to_float64('1.2') |
-+-------------------+
-| 1.2 |
-+-------------------+
-
-SELECT to_int8('123');
-+----------------+
-| to_int8('123') |
-+----------------+
-| 123 |
-+----------------+
-
-SELECT to_null(10);
-+-------------+
-| to_null(10) |
-+-------------+
-| NULL |
-+-------------+
-
-SELECT to_string(10);
-+---------------+
-| to_string(10) |
-+---------------+
-| 10 |
-+---------------+
-```
diff --git a/docs/doc/15-sql-functions/80-uuid-functions/index.md b/docs/doc/15-sql-functions/80-uuid-functions/index.md
index e47c531d203ff..021617706c052 100644
--- a/docs/doc/15-sql-functions/80-uuid-functions/index.md
+++ b/docs/doc/15-sql-functions/80-uuid-functions/index.md
@@ -4,5 +4,5 @@ title: 'UUID Functions'
| Function | Description | Example | Result |
|--------------------------------------|-----------------------------------------------------------------|------------------------|--------------------------------------|
-| **GEN_RANDOM_UUID** | Generate a random UUID based on v4. | **gen_random_uuid()** | ab1bce12-4508-4d11-bd96-c42e9e7eefdd |
+| **GEN_RANDOM_UUID()** | Generate a random UUID based on v4. | **GEN_RANDOM_UUID()** | ab1bce12-4508-4d11-bd96-c42e9e7eefdd |
| **UUID()** | Generate a UUID. | **UUID()** | c72fe96b-3662-4f49-a63b-345b17ceebd6 |
diff --git a/docs/doc/20-develop/00-golang.md b/docs/doc/20-develop/00-golang.md
deleted file mode 100644
index ec8daef420540..0000000000000
--- a/docs/doc/20-develop/00-golang.md
+++ /dev/null
@@ -1,157 +0,0 @@
----
-title: How to Work With Databend in Golang
-sidebar_label: Golang
-description:
- How to work with Databend in Golang.
----
-
-## Before You Begin
-
-* **Databend :** Make sure Databend is running and accessible, see [How to deploy Databend](/doc/deploy).
-* [How to Create User](../14-sql-commands/00-ddl/30-user/01-user-create-user.md)
-* [How to Grant Privileges to User](../14-sql-commands/00-ddl/30-user/10-grant-privileges.md)
-
-## Create Databend User
-
-```shell
-mysql -h127.0.0.1 -uroot -P3307
-```
-
-### Create a User
-
-```sql
-CREATE USER user1 IDENTIFIED BY 'abc123';
-```
-
-### Grants Privileges
-
-Grants `ALL` privileges to the user `user1`:
-```sql
-GRANT ALL on *.* TO user1;
-```
-
-## Golang
-
-This guideline show how to connect and query to Databend using Golang. We will be creating a table named `books` and insert a row, then query it.
-
-### main.go
-
-```text title='main.go'
-package main
-
-import (
- "database/sql"
- "fmt"
- "log"
-
- _ "github.com/go-sql-driver/mysql"
-)
-
-const (
- username = "user1"
- password = "abc123"
- hostname = "127.0.0.1:3307"
-)
-
-type Book struct {
- Title string
- Author string
- Date string
-}
-
-func dsn() string {
- // Note Databend do not support prepared statements.
- // set interpolateParams to make placeholders (?) in calls to db.Query() and db.Exec() interpolated into a single query string with given parameters.
- // ref https://github.com/go-sql-driver/mysql#interpolateparams
- return fmt.Sprintf("%s:%s@tcp(%s)/?interpolateParams=true", username, password, hostname)
-}
-
-func main() {
- db, err := sql.Open("mysql", dsn())
-
- if err != nil {
- log.Fatal(err)
- }
- defer db.Close()
-
- err = db.Ping()
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Connected")
-
- // Create db if do not exist
- dbSql := "CREATE DATABASE IF NOT EXISTS book_db"
- _, err = db.Exec(dbSql)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Create database book_db success")
-
- // Use book_db database
- _, err = db.Exec("USE book_db")
- if err != nil {
- log.Fatal(err)
- }
-
- // Create table.
- sql := "create table if not exists books(title VARCHAR, author VARCHAR, date VARCHAR)"
- _, err = db.Exec(sql)
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Create table: books")
-
- // Insert 1 row.
- _, err = db.Exec("INSERT INTO books VALUES(?, ?, ?)", "mybook", "author", "2022")
- if err != nil {
- log.Fatal(err)
- }
- log.Println("Insert 1 row")
-
- // Select.
- res, err := db.Query("SELECT * FROM books")
- if err != nil {
- log.Fatal(err)
- }
-
- for res.Next() {
- var book Book
- err := res.Scan(&book.Title, &book.Author, &book.Date)
- if err != nil {
- log.Fatal(err)
- }
-
- log.Printf("Select:%v", book)
- }
-
-}
-```
-
-### Golang mod
-
-```text
-go mod init databend-golang
-```
-
-```text title='go.mod'
-module databend-golang
-
-go 1.18
-
-require github.com/go-sql-driver/mysql v1.6.0
-```
-
-### Run main.go
-
-```shell
-go run main.go
-```
-
-```text title='Outputs'
-2022/04/13 12:20:07 Connected
-2022/04/13 12:20:07 Create database book_db success
-2022/04/13 12:20:07 Create table: books
-2022/04/13 12:20:07 Insert 1 row
-2022/04/13 12:20:08 Select:{mybook author 2022}
-```
diff --git a/docs/doc/20-develop/01-python.md b/docs/doc/20-develop/01-python.md
deleted file mode 100644
index 744f9d1f6e8d1..0000000000000
--- a/docs/doc/20-develop/01-python.md
+++ /dev/null
@@ -1,109 +0,0 @@
----
-title: How to Work With Databend in Python
-sidebar_label: Python
-description:
- How to work with Databend in Python.
----
-
-## Before You Begin
-
-* **Databend :** Make sure Databend is running and accessible, see [How to deploy Databend](/doc/deploy).
-* [How to Create User](../14-sql-commands/00-ddl/30-user/01-user-create-user.md)
-* [How to Grant Privileges to User](../14-sql-commands/00-ddl/30-user/10-grant-privileges.md)
-
-## Create Databend User
-
-```shell
-mysql -h127.0.0.1 -uroot -P3307
-```
-
-### Create a User
-
-```sql
-CREATE USER user1 IDENTIFIED BY 'abc123';
-```
-
-### Grants Privileges
-
-Grants `ALL` privileges to the user `user1`:
-```sql
-GRANT ALL ON *.* TO user1;
-```
-
-## Python
-
-This guideline show how to connect and query to Databend using Python.
-
-We will be creating a table named `books` and insert a row, then query it.
-
-### Using mysql.connector
-
-```shell
-pip install mysql-connector-python
-```
-
-```python title='main.py'
-#!/usr/bin/env python3
-import mysql.connector
-
-cnx = mysql.connector.connect(user='user1', password='abc123',
- host='127.0.0.1',
- port = 3307,
- database='')
-
-# Create database, table.
-cursor = cnx.cursor()
-cursor.execute("CREATE DATABASE IF NOT EXISTS book_db")
-cursor.execute("USE book_db")
-cursor.execute("CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)")
-
-# Insert new book.
-add_book = ("INSERT INTO books "
- "(title, author, date) "
- "VALUES (%s, %s, %s)")
-data_book = ('mybook', 'author', '2022')
-cursor.execute(add_book, data_book)
-
-# Query.
-query = ("SELECT * FROM books")
-cursor.execute(query)
-for (title, author, date) in cursor:
- print("{} {} {}".format(title, author, date))
-
-cursor.close()
-cnx.close()
-```
-
-Run `python main.py`:
-```text
-mybook author 2022
-```
-
-### Using sqlalchemy
-
-```shell
-pip install sqlalchemy
-```
-
-```python title='main.py'
-#!/usr/bin/env python3
-
-import sqlalchemy
-
-engine = sqlalchemy.create_engine("mysql+pymysql://user1:abc123@localhost:3307/")
-conn = engine.connect()
-conn.execute("CREATE DATABASE IF NOT EXISTS book_db")
-conn.execute("USE book_db")
-conn.execute("CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)")
-conn.execute("INSERT INTO books VALUES('mybook', 'author', '2022')")
-results = conn.execute('SELECT * FROM books').fetchall()
-for result in results:
- print(result)
-conn.execute('drop database book_db')
-
-```
-
-Run `python main.py`:
-```text
-('mybook', 'author', '2022')
-```
diff --git a/docs/doc/20-develop/02-nodejs.md b/docs/doc/20-develop/02-nodejs.md
deleted file mode 100644
index 63ccd14fab4b0..0000000000000
--- a/docs/doc/20-develop/02-nodejs.md
+++ /dev/null
@@ -1,96 +0,0 @@
----
-title: How to Work With Databend in Node.js
-sidebar_label: Node.js
-description:
- How to work with Databend in Node.js.
----
-
-## Before You Begin
-
-* **Databend :** Make sure Databend is running and accessible, see [How to deploy Databend](/doc/deploy).
-* [How to Create User](../14-sql-commands/00-ddl/30-user/01-user-create-user.md)
-* [How to Grant Privileges to User](../14-sql-commands/00-ddl/30-user/10-grant-privileges.md)
-
-## Create Databend User
-
-```shell
-mysql -h127.0.0.1 -uroot -P3307
-```
-
-### Create a User
-
-```sql
-CREATE USER user1 IDENTIFIED BY 'abc123';
-```
-
-### Grants Privileges
-
-Grants `ALL` privileges to the user `user1`:
-```sql
-GRANT ALL ON *.* TO user1;
-```
-
-## Node.js
-
-This guideline show how to connect and query to Databend using Node.js.
-
-We will be creating a table named `books` and insert a row, then query it.
-
-```text
-npm install --save mysql
-```
-
-```js title='databend.js'
-const mysql = require('mysql');
-const con = mysql.createConnection({
- host: 'localhost',
- port: 3307,
- user: 'user1',
- password: 'abc123',
-});
-
-con.connect((err) => {
- if (err) throw err;
- console.log('Connected to Databend Server!');
-
- var sql = "CREATE DATABASE IF NOT EXISTS book_db";
- con.query(sql, function (err, result) {
- if (err) throw err;
- console.log("Dataabse created");
- });
-
- var sql = "USE book_db";
- con.query(sql, function (err, result) {
- if (err) throw err;
- });
-
-
- var sql = "CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)";
- con.query(sql, function (err, result) {
- if (err) throw err;
- console.log("Table created");
- });
-
- var sql = "INSERT INTO books VALUES('mybook', 'author', '2022')";
- con.query(sql, function (err, result) {
- if (err) throw err;
- console.log("1 record inserted");
- });
-
- con.query("SELECT * FROM books", function (err, result, fields) {
- if (err) throw err;
- console.log(result);
- });
-
-});
-```
-
-Run `nodejs databend.js`:
-
-```text
-Connected to Databend Server!
-Dataabse created
-Table created
-1 record inserted
-[ RowDataPacket { title: 'mybook', author: 'author', date: '2022' } ]
-```
diff --git a/docs/doc/20-develop/03-java.md b/docs/doc/20-develop/03-java.md
deleted file mode 100644
index 17178bf271f1b..0000000000000
--- a/docs/doc/20-develop/03-java.md
+++ /dev/null
@@ -1,127 +0,0 @@
----
-title: How to Work With Databend in Java
-sidebar_label: Java
-description:
- How to work with Databend in Java.
----
-
-## Before You Begin
-
-* **Databend :** Make sure Databend is running and accessible, see [How to deploy Databend](/doc/deploy).
-* [How to Create User](../14-sql-commands/00-ddl/30-user/01-user-create-user.md)
-* [How to Grant Privileges to User](../14-sql-commands/00-ddl/30-user/10-grant-privileges.md)
-
-## Create Databend User
-
-```shell
-mysql -h127.0.0.1 -uroot -P3307
-```
-
-### Create a User
-
-```sql
-CREATE USER user1 IDENTIFIED BY 'abc123';
-```
-
-### Grants Privileges
-
-Grants `ALL` privileges to the user `user1`:
-```sql
-GRANT ALL on *.* TO user1;
-```
-
-## Java
-
-This topic shows how to connect and query Databend using JDBC. We will create a table named books, insert a row, and then query data from the table.
-
-### demo.java
-
-```java title='demo.java'
-import java.sql.*;
-
-public class demo {
- static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
- static final String DB_URL = "jdbc:mysql://127.0.0.1:3307/default";
-
- static final String USER = "user1";
- static final String PASS = "abc123";
-
- public static void main(String[] args) {
- Connection conn = null;
- Statement stmt = null;
- try{
- Class.forName(JDBC_DRIVER);
- conn = DriverManager.getConnection(DB_URL,USER,PASS);
-
- stmt = conn.createStatement();
- String create_sql = "CREATE DATABASE IF NOT EXISTS book_db";
- int rs1 = stmt.executeUpdate(create_sql);
-
- String use_sql = "USE book_db";
- int rs2 = stmt.executeUpdate(use_sql);
-
- String ct_sql = "CREATE TABLE IF NOT EXISTS books(title VARCHAR, author VARCHAR, date VARCHAR)";
- int rs3 = stmt.executeUpdate(ct_sql);
-
-
- // Insert new book.
- String title = "mybook";
- String author = "author";
- String date = "2022";
- String add_book = "INSERT INTO books (title, author, date) VALUES ('"+ title +"', '"+ author +"', '" + date + "')";
- int rs4 = stmt.executeUpdate(add_book);
-
-
- // Select book
- String sql = "SELECT * FROM books";
- ResultSet rs = stmt.executeQuery(sql);
-
- while (rs.next()) {
- String col1 = rs.getString("title");
- String col2 = rs.getString("author");
- String col3 = rs.getString("date");
-
- System.out.print("title: " + col1 + ", author: " + col2 + ", date: " + col3);
- }
- // Close conn
- rs.close();
- stmt.close();
- conn.close();
- } catch(SQLException se) {
- // throw JDBC err
- se.printStackTrace();
- } catch(Exception e) {
- // throw Class.forName err
- e.printStackTrace();
- } finally {
- // Close source
- try{
- if(stmt!=null) stmt.close();
- } catch(SQLException se2) {
- }
- try{
- if (conn!=null) conn.close();
- } catch(SQLException se) {
- se.printStackTrace();
- }
- }
- }
-}
-```
-
-### Run demo.java
-
-In this case:
-
-The demo classpath is located at /home/eason/database/source-code/test/out/test/test
-
-The demo classpath is located at /home/eason/Downloads/jar_files/mysql-connector-java-5.1.48.jar
-
-```shell
-$ ~/.jdks/openjdk-17.0.1/bin/java -Dfile.encoding=UTF-8 -classpath /home/eason/database/source-code/test/out/test/test:/home/eason/Downloads/jar_files/mysql-connector-java-5.1.48.jar demo
-title: mybook, author: author, date: 2022
-```
-
-```text title='Outputs'
-title: mybook, author: author, date: 2022
-```
diff --git a/docs/doc/90-contributing/01-rfcs/20230213-query-result-cache.md b/docs/doc/90-contributing/01-rfcs/20230213-query-result-cache.md
index 1285936578819..0a9c24fe5b4b4 100644
--- a/docs/doc/90-contributing/01-rfcs/20230213-query-result-cache.md
+++ b/docs/doc/90-contributing/01-rfcs/20230213-query-result-cache.md
@@ -139,6 +139,26 @@ The table contains such information:
- `result_size`: the size of the result cache (bytes).
- `location`: the location of the result cache file.
+### Table function `RESULT_SCAN`
+
+`RESULT_SCAN` is a useful table function to retrieve the result set of a previous query.
+
+It can be used like:
+
+```sql
+select * from RESULT_SCAN('');
+select * from RESULT_SCAN(LAST_QUERY_ID());
+```
+
+If the previous query result is cached, we can get the result set quickly from query result cache.
+
### Non-deterministic functions
Some functions are non-deterministic, such as `now()`, `rand()`, `uuid()`, etc. If these functions are used in the query, the result will not be cached.
+
+## References
+
+- [Query Cache in ClickHouse](https://clickhouse.com/docs/en/operations/query-cache/)
+- [Blog about the query cache in ClickHouse](https://clickhouse.com/blog/introduction-to-the-clickhouse-query-cache-and-design)
+- [RESULT_SCAN in snowflake](https://docs.snowflake.com/en/sql-reference/functions/result_scan)
+- [Tuning the Result Cache in Oracle](https://docs.oracle.com/en/database/oracle/oracle-database/19/tgdba/tuning-result-cache.html)
\ No newline at end of file
diff --git a/scripts/ci/deploy/config/databend-query-node-1.toml b/scripts/ci/deploy/config/databend-query-node-1.toml
index c404bf476004a..ab03f216ff1c7 100644
--- a/scripts/ci/deploy/config/databend-query-node-1.toml
+++ b/scripts/ci/deploy/config/databend-query-node-1.toml
@@ -54,7 +54,7 @@ default_compression = 'zstd'
[log]
[log.file]
-level = "WARN"
+level = "INFO"
format = "text"
dir = "./.databend/logs_1"
diff --git a/scripts/ci/deploy/config/databend-query-node-2.toml b/scripts/ci/deploy/config/databend-query-node-2.toml
index 3436aa97d972b..46460b68ee689 100644
--- a/scripts/ci/deploy/config/databend-query-node-2.toml
+++ b/scripts/ci/deploy/config/databend-query-node-2.toml
@@ -37,7 +37,7 @@ default_compression = 'zstd'
[log]
[log.file]
-level = "ERROR"
+level = "INFO"
format = "text"
dir = "./.databend/logs_2"
diff --git a/scripts/ci/deploy/config/databend-query-node-3.toml b/scripts/ci/deploy/config/databend-query-node-3.toml
index 80de1fc49994d..1d27ac466c042 100644
--- a/scripts/ci/deploy/config/databend-query-node-3.toml
+++ b/scripts/ci/deploy/config/databend-query-node-3.toml
@@ -38,7 +38,7 @@ default_compression = 'zstd'
[log]
[log.file]
-level = "ERROR"
+level = "INFO"
format = "text"
dir = "./.databend/logs_3"
diff --git a/src/common/hashtable/Cargo.toml b/src/common/hashtable/Cargo.toml
index 1a8b9383094a2..7d90d0ccf148a 100644
--- a/src/common/hashtable/Cargo.toml
+++ b/src/common/hashtable/Cargo.toml
@@ -20,8 +20,8 @@ common-base = { path = "../base" }
ahash = { version = "0.8.2", features = ["no-rng"] }
bumpalo = "3.10.0"
cfg-if = "1.0.0"
+ethnum = { version = "1.3" }
ordered-float = { workspace = true, features = ["serde"] }
-primitive-types = "0.12.0"
[dev-dependencies]
rand = "0.8.5"
diff --git a/src/common/hashtable/src/partitioned_hashtable.rs b/src/common/hashtable/src/partitioned_hashtable.rs
index d1541670d2dfc..7b6103d472a6c 100644
--- a/src/common/hashtable/src/partitioned_hashtable.rs
+++ b/src/common/hashtable/src/partitioned_hashtable.rs
@@ -16,6 +16,7 @@ use std::collections::VecDeque;
use std::iter::TrustedLen;
use std::mem::MaybeUninit;
use std::slice::IterMut;
+use std::vec::IntoIter;
use crate::FastHash;
use crate::HashSet;
@@ -42,6 +43,18 @@ impl
pub fn iter_tables_mut(&mut self) -> IterMut<'_, Impl> {
self.tables.iter_mut()
}
+
+ pub fn into_iter_tables(self) -> IntoIter {
+ self.tables.into_iter()
+ }
+
+ // #Unsafe the caller must ensure that the hashtable is not used after take_inner_tables
+ pub unsafe fn pop_first_inner_table(&mut self) -> Option {
+ match self.tables.is_empty() {
+ true => None,
+ false => Some(self.tables.remove(0)),
+ }
+ }
}
/// crc32c hash will return a 32-bit hash value even it's type is u64.
diff --git a/src/common/hashtable/src/traits.rs b/src/common/hashtable/src/traits.rs
index 701c1b5077995..00acd1471d7e5 100644
--- a/src/common/hashtable/src/traits.rs
+++ b/src/common/hashtable/src/traits.rs
@@ -15,13 +15,13 @@
// To avoid RUSTFLAGS="-C target-feature=+sse4.2" warning.
#![allow(unused_imports)]
use std::hash::BuildHasher;
+use std::hash::Hasher;
use std::iter::TrustedLen;
use std::mem::MaybeUninit;
use std::num::NonZeroU64;
+use ethnum::U256;
use ordered_float::OrderedFloat;
-use primitive_types::U256;
-use primitive_types::U512;
/// # Safety
///
@@ -82,29 +82,12 @@ impl_key_for_primitive_types!(i128);
unsafe impl Keyable for U256 {
#[inline(always)]
fn equals_zero(this: &Self) -> bool {
- U256::is_zero(this)
+ *this == U256::ZERO
}
#[inline(always)]
fn is_zero(this: &MaybeUninit) -> bool {
- U256::is_zero(unsafe { this.assume_init_ref() })
- }
-
- #[inline(always)]
- fn hash(&self) -> u64 {
- self.fast_hash()
- }
-}
-
-unsafe impl Keyable for U512 {
- #[inline(always)]
- fn is_zero(this: &MaybeUninit) -> bool {
- U512::is_zero(unsafe { this.assume_init_ref() })
- }
-
- #[inline(always)]
- fn equals_zero(this: &Self) -> bool {
- U512::is_zero(this)
+ *unsafe { this.assume_init_ref() } == U256::ZERO
}
#[inline(always)]
@@ -257,7 +240,8 @@ impl FastHash for U256 {
use std::arch::x86_64::_mm_crc32_u64;
let mut value = u64::MAX;
for x in self.0 {
- value = unsafe { _mm_crc32_u64(value, x) };
+ value = unsafe { _mm_crc32_u64(value, x as u64) };
+ value = unsafe { _mm_crc32_u64(value, (x >> 64) as u64) };
}
value
} else {
@@ -265,31 +249,7 @@ impl FastHash for U256 {
let state = ahash::RandomState::with_seeds(SEEDS[0], SEEDS[1], SEEDS[2], SEEDS[3]);
let mut hasher = state.build_hasher();
for x in self.0 {
- hasher.write_u64(x);
- }
- hasher.finish()
- }
- }
- }
-}
-
-impl FastHash for U512 {
- #[inline(always)]
- fn fast_hash(&self) -> u64 {
- cfg_if::cfg_if! {
- if #[cfg(target_feature = "sse4.2")] {
- use std::arch::x86_64::_mm_crc32_u64;
- let mut value = u64::MAX;
- for x in self.0 {
- value = unsafe { _mm_crc32_u64(value, x) };
- }
- value
- } else {
- use std::hash::Hasher;
- let state = ahash::RandomState::with_seeds(SEEDS[0], SEEDS[1], SEEDS[2], SEEDS[3]);
- let mut hasher = state.build_hasher();
- for x in self.0 {
- hasher.write_u64(x);
+ hasher.write_u128(x);
}
hasher.finish()
}
diff --git a/src/common/io/src/file_split.rs b/src/common/io/src/file_split.rs
deleted file mode 100644
index 5f1154a728a42..0000000000000
--- a/src/common/io/src/file_split.rs
+++ /dev/null
@@ -1,51 +0,0 @@
-// Copyright 2022 Datafuse Labs.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use std::borrow::Cow;
-
-#[derive(Debug)]
-pub struct FileSplitCow<'a> {
- pub path: Option,
- pub start_offset: usize,
- pub start_row: usize,
- pub buf: Cow<'a, [u8]>,
-}
-
-#[derive(Debug)]
-pub struct FileSplit {
- pub path: Option,
- pub start_offset: usize,
- pub start_row: usize,
- pub buf: Vec,
-}
-
-impl FileSplit {
- pub fn to_cow(self) -> FileSplitCow<'static> {
- FileSplitCow {
- path: self.path,
- start_offset: self.start_offset,
- start_row: self.start_row,
- buf: Cow::from(self.buf),
- }
- }
-
- pub fn from_cow(data: FileSplitCow<'_>) -> Self {
- Self {
- path: data.path,
- start_offset: data.start_offset,
- start_row: data.start_row,
- buf: data.buf.into_owned(),
- }
- }
-}
diff --git a/src/common/io/src/lib.rs b/src/common/io/src/lib.rs
index de3a7b8d2d096..718fc5f9d74ca 100644
--- a/src/common/io/src/lib.rs
+++ b/src/common/io/src/lib.rs
@@ -32,7 +32,6 @@ mod binary_write;
pub mod cursor_ext;
mod escape;
-mod file_split;
mod format_settings;
mod position;
mod serialization;
diff --git a/src/common/io/src/prelude.rs b/src/common/io/src/prelude.rs
index c7bee434055f9..e67c8b6522ebf 100644
--- a/src/common/io/src/prelude.rs
+++ b/src/common/io/src/prelude.rs
@@ -18,7 +18,6 @@ pub use bytes::BytesMut;
pub use crate::binary_read::BinaryRead;
pub use crate::binary_write::put_uvarint;
pub use crate::binary_write::BinaryWrite;
-pub use crate::file_split::*;
pub use crate::format_settings::FormatSettings;
pub use crate::position::*;
pub use crate::serialization::*;
diff --git a/src/common/storage/src/operator.rs b/src/common/storage/src/operator.rs
index cec42d94bbe4c..2ecb20987d61b 100644
--- a/src/common/storage/src/operator.rs
+++ b/src/common/storage/src/operator.rs
@@ -36,6 +36,7 @@ use common_meta_app::storage::StorageOssConfig;
use common_meta_app::storage::StorageParams;
use common_meta_app::storage::StorageRedisConfig;
use common_meta_app::storage::StorageS3Config;
+use common_meta_app::storage::StorageWebhdfsConfig;
use opendal::layers::ImmutableIndexLayer;
use opendal::layers::LoggingLayer;
use opendal::layers::MetricsLayer;
@@ -66,6 +67,7 @@ pub fn init_operator(cfg: &StorageParams) -> Result {
StorageParams::S3(cfg) => build_operator(init_s3_operator(cfg)?),
StorageParams::Oss(cfg) => build_operator(init_oss_operator(cfg)?),
StorageParams::Redis(cfg) => build_operator(init_redis_operator(cfg)?),
+ StorageParams::Webhdfs(cfg) => build_operator(init_webhdfs_operator(cfg)?),
v => {
return Err(Error::new(
ErrorKind::InvalidInput,
@@ -294,6 +296,17 @@ fn init_redis_operator(v: &StorageRedisConfig) -> Result {
Ok(builder.build()?)
}
+/// init_webhdfs_operator will init a WebHDFS operator
+fn init_webhdfs_operator(v: &StorageWebhdfsConfig) -> Result {
+ let mut builder = services::Webhdfs::default();
+
+ builder.endpoint(&v.endpoint_url);
+ builder.root(&v.root);
+ builder.delegation(&v.delegation);
+
+ Ok(builder.build()?)
+}
+
/// DataOperator is the operator to access persist data services.
///
/// # Notes
diff --git a/src/meta/app/src/storage/storage_params.rs b/src/meta/app/src/storage/storage_params.rs
index 176ddbef82998..737cdb0e569c9 100644
--- a/src/meta/app/src/storage/storage_params.rs
+++ b/src/meta/app/src/storage/storage_params.rs
@@ -37,6 +37,7 @@ pub enum StorageParams {
Oss(StorageOssConfig),
S3(StorageS3Config),
Redis(StorageRedisConfig),
+ Webhdfs(StorageWebhdfsConfig),
/// None means this storage type is none.
///
@@ -70,6 +71,7 @@ impl StorageParams {
StorageParams::S3(v) => v.endpoint_url.starts_with("https://"),
StorageParams::Gcs(v) => v.endpoint_url.starts_with("https://"),
StorageParams::Redis(_) => false,
+ StorageParams::Webhdfs(v) => v.endpoint_url.starts_with("https://"),
StorageParams::None => false,
}
}
@@ -91,6 +93,7 @@ impl StorageParams {
StorageParams::S3(v) => v.root = f(&v.root),
StorageParams::Gcs(v) => v.root = f(&v.root),
StorageParams::Redis(v) => v.root = f(&v.root),
+ StorageParams::Webhdfs(v) => v.root = f(&v.root),
StorageParams::None => {}
};
@@ -156,6 +159,9 @@ impl Display for StorageParams {
v.db, v.root, v.endpoint_url
)
}
+ StorageParams::Webhdfs(v) => {
+ write!(f, "webhdfs | root={},endpoint={}", v.root, v.endpoint_url)
+ }
StorageParams::None => {
write!(f, "none",)
}
@@ -472,6 +478,26 @@ impl Debug for StorageRedisConfig {
}
}
+/// config for WebHDFS Storage Service
+#[derive(Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
+pub struct StorageWebhdfsConfig {
+ pub endpoint_url: String,
+ pub root: String,
+ pub delegation: String,
+}
+
+impl Debug for StorageWebhdfsConfig {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ let mut ds = f.debug_struct("StorageWebhdfsConfig");
+
+ ds.field("endpoint_url", &self.endpoint_url)
+ .field("root", &self.root);
+
+ ds.field("delegation", &mask_string(&self.delegation, 3));
+
+ ds.finish()
+ }
+}
/// Mask a string by "******", but keep `unmask_len` of suffix.
///
/// Copied from `common-base` so that we don't need to depend on it.
diff --git a/src/meta/proto-conv/src/config_from_to_protobuf_impl.rs b/src/meta/proto-conv/src/config_from_to_protobuf_impl.rs
index bcee566f25c13..3b0316f27af9d 100644
--- a/src/meta/proto-conv/src/config_from_to_protobuf_impl.rs
+++ b/src/meta/proto-conv/src/config_from_to_protobuf_impl.rs
@@ -16,6 +16,7 @@ use common_meta_app::storage::StorageFsConfig;
use common_meta_app::storage::StorageGcsConfig;
use common_meta_app::storage::StorageOssConfig;
use common_meta_app::storage::StorageS3Config;
+use common_meta_app::storage::StorageWebhdfsConfig;
use common_protos::pb;
use crate::reader_check_msg;
@@ -157,3 +158,34 @@ impl FromToProto for StorageOssConfig {
})
}
}
+
+impl FromToProto for StorageWebhdfsConfig {
+ type PB = pb::WebhdfsStorageConfig;
+ fn get_pb_ver(p: &Self::PB) -> u64 {
+ p.version
+ }
+
+ fn from_pb(p: Self::PB) -> Result
+ where Self: Sized {
+ reader_check_msg(p.version, p.min_reader_ver)?;
+
+ Ok(StorageWebhdfsConfig {
+ endpoint_url: p.endpoint_url,
+ root: p.root,
+ delegation: p.delegation,
+ })
+ }
+
+ fn to_pb(&self) -> Result {
+ Ok(pb::WebhdfsStorageConfig {
+ version: VER,
+ min_reader_ver: MIN_READER_VER,
+ endpoint_url: self.endpoint_url.clone(),
+ root: self.root.clone(),
+ delegation: self.delegation.clone(),
+
+ username: String::new(), // reserved for future use
+ password: String::new(), // reserved for future use
+ })
+ }
+}
diff --git a/src/meta/proto-conv/src/user_from_to_protobuf_impl.rs b/src/meta/proto-conv/src/user_from_to_protobuf_impl.rs
index 61098a8c91a20..f58b8d59e6973 100644
--- a/src/meta/proto-conv/src/user_from_to_protobuf_impl.rs
+++ b/src/meta/proto-conv/src/user_from_to_protobuf_impl.rs
@@ -537,6 +537,9 @@ impl FromToProto for mt::storage::StorageParams {
Some(pb::user_stage_info::stage_storage::Storage::Oss(s)) => Ok(
mt::storage::StorageParams::Oss(mt::storage::StorageOssConfig::from_pb(s)?),
),
+ Some(pb::user_stage_info::stage_storage::Storage::Webhdfs(s)) => Ok(
+ mt::storage::StorageParams::Webhdfs(mt::storage::StorageWebhdfsConfig::from_pb(s)?),
+ ),
None => Err(Incompatible {
reason: "StageStorage.storage cannot be None".to_string(),
}),
@@ -557,6 +560,11 @@ impl FromToProto for mt::storage::StorageParams {
mt::storage::StorageParams::Oss(v) => Ok(pb::user_stage_info::StageStorage {
storage: Some(pb::user_stage_info::stage_storage::Storage::Oss(v.to_pb()?)),
}),
+ mt::storage::StorageParams::Webhdfs(v) => Ok(pb::user_stage_info::StageStorage {
+ storage: Some(pb::user_stage_info::stage_storage::Storage::Webhdfs(
+ v.to_pb()?,
+ )),
+ }),
others => Err(Incompatible {
reason: format!("stage type: {} not supported", others),
}),
diff --git a/src/meta/proto-conv/src/util.rs b/src/meta/proto-conv/src/util.rs
index 33ecd3583dbbf..c86127deec6f4 100644
--- a/src/meta/proto-conv/src/util.rs
+++ b/src/meta/proto-conv/src/util.rs
@@ -91,6 +91,10 @@ const META_CHANGE_LOG: &[(u64, &str)] = &[
29,
"2023-02-23: Add: metadata.proto/DataType EmptyMap types",
),
+ (
+ 30,
+ "2023-02-21: Add: config.proto/WebhdfsStorageConfig; Modify: user.proto/UserStageInfo::StageStorage",
+ ),
// Dear developer:
// If you're gonna add a new metadata version, you'll have to add a test for it.
// You could just copy an existing test file(e.g., `../tests/it/v024_table_meta.rs`)
diff --git a/src/meta/proto-conv/tests/it/main.rs b/src/meta/proto-conv/tests/it/main.rs
index dd8b83f86d190..e79c18df99f92 100644
--- a/src/meta/proto-conv/tests/it/main.rs
+++ b/src/meta/proto-conv/tests/it/main.rs
@@ -36,3 +36,4 @@ mod v026_schema;
mod v027_schema;
mod v028_schema;
mod v029_schema;
+mod v030_user_stage;
diff --git a/src/meta/proto-conv/tests/it/user_proto_conv.rs b/src/meta/proto-conv/tests/it/user_proto_conv.rs
index b5a10e10ffaf4..254c49b05a2f4 100644
--- a/src/meta/proto-conv/tests/it/user_proto_conv.rs
+++ b/src/meta/proto-conv/tests/it/user_proto_conv.rs
@@ -27,6 +27,7 @@ use common_meta_app::storage::StorageGcsConfig;
use common_meta_app::storage::StorageOssConfig;
use common_meta_app::storage::StorageParams;
use common_meta_app::storage::StorageS3Config;
+use common_meta_app::storage::StorageWebhdfsConfig;
use common_proto_conv::FromToProto;
use common_proto_conv::Incompatible;
use common_proto_conv::VER;
@@ -308,6 +309,43 @@ pub(crate) fn test_oss_stage_info() -> mt::principal::UserStageInfo {
}
}
+// version 29 added WebHDFS as a stage backend, should be tested
+pub(crate) fn test_webhdfs_stage_info() -> mt::principal::UserStageInfo {
+ mt::principal::UserStageInfo {
+ stage_name: "webhdfs://path/to/stage/files".to_string(),
+ stage_type: mt::principal::StageType::External,
+ stage_params: mt::principal::StageParams {
+ storage: StorageParams::Webhdfs(StorageWebhdfsConfig {
+ endpoint_url: "https://webhdfs.example.com".to_string(),
+ root: "/path/to/stage/files".to_string(),
+ delegation: "".to_string(),
+ }),
+ },
+ file_format_options: mt::principal::FileFormatOptions {
+ format: mt::principal::StageFileFormatType::Json,
+ skip_header: 1024,
+ field_delimiter: "|".to_string(),
+ record_delimiter: "//".to_string(),
+ nan_display: "NaN".to_string(),
+ escape: "".to_string(),
+ compression: mt::principal::StageFileCompression::Bz2,
+ row_tag: "row".to_string(),
+ quote: "".to_string(),
+ name: None,
+ },
+ copy_options: mt::principal::CopyOptions {
+ on_error: mt::principal::OnErrorMode::SkipFileNum(3141),
+ size_limit: 1038,
+ split_size: 0,
+ purge: true,
+ single: false,
+ max_file_size: 0,
+ },
+ comment: "test".to_string(),
+ ..Default::default()
+ }
+}
+
pub(crate) fn test_stage_file() -> mt::principal::StageFile {
let dt = NaiveDateTime::new(
NaiveDate::from_ymd(2022, 9, 16),
@@ -479,6 +517,25 @@ fn test_user_incompatible() -> anyhow::Result<()> {
)
}
+ {
+ let webhdfs_stage_info = test_webhdfs_stage_info();
+ let mut p = webhdfs_stage_info.to_pb()?;
+ p.ver = VER + 1;
+ p.min_reader_ver = VER + 1;
+
+ let res = mt::principal::UserStageInfo::from_pb(p);
+ assert_eq!(
+ Incompatible {
+ reason: format!(
+ "executable ver={} is smaller than the min reader version({}) that can read this message",
+ VER,
+ VER + 1
+ )
+ },
+ res.unwrap_err()
+ )
+ }
+
Ok(())
}
diff --git a/src/meta/proto-conv/tests/it/user_stage.rs b/src/meta/proto-conv/tests/it/user_stage.rs
index 51fee87d76f04..38cb91c97b387 100644
--- a/src/meta/proto-conv/tests/it/user_stage.rs
+++ b/src/meta/proto-conv/tests/it/user_stage.rs
@@ -23,6 +23,7 @@ use crate::user_proto_conv::test_internal_stage_info_v17;
use crate::user_proto_conv::test_oss_stage_info;
use crate::user_proto_conv::test_s3_stage_info;
use crate::user_proto_conv::test_user_stage_info_v18;
+use crate::user_proto_conv::test_webhdfs_stage_info;
#[test]
fn test_user_stage_fs_latest() -> anyhow::Result<()> {
@@ -48,6 +49,67 @@ fn test_user_stage_oss_latest() -> anyhow::Result<()> {
Ok(())
}
+#[test]
+fn test_user_stage_webhdfs_latest() -> anyhow::Result<()> {
+ common::test_pb_from_to("user_stage_webhdfs", test_webhdfs_stage_info())?;
+ Ok(())
+}
+
+#[test]
+fn test_user_stage_webhdfs_v30() -> anyhow::Result<()> {
+ // Encoded data of version 30 of common_meta_app::principal::user_stage::UserStageInfo:
+ // It is generated with common::test_pb_from_to().
+ let user_stage_info_v30 = vec![
+ 10, 29, 119, 101, 98, 104, 100, 102, 115, 58, 47, 47, 112, 97, 116, 104, 47, 116, 111, 47,
+ 115, 116, 97, 103, 101, 47, 102, 105, 108, 101, 115, 16, 1, 26, 81, 10, 79, 42, 77, 10, 27,
+ 104, 116, 116, 112, 115, 58, 47, 47, 119, 101, 98, 104, 100, 102, 115, 46, 101, 120, 97,
+ 109, 112, 108, 101, 46, 99, 111, 109, 18, 20, 47, 112, 97, 116, 104, 47, 116, 111, 47, 115,
+ 116, 97, 103, 101, 47, 102, 105, 108, 101, 115, 26, 18, 60, 100, 101, 108, 101, 103, 97,
+ 116, 105, 111, 110, 95, 116, 111, 107, 101, 110, 62, 160, 6, 30, 168, 6, 24, 34, 30, 8, 1,
+ 16, 128, 8, 26, 1, 124, 34, 2, 47, 47, 40, 2, 58, 3, 114, 111, 119, 66, 3, 78, 97, 78, 160,
+ 6, 30, 168, 6, 24, 42, 10, 10, 3, 32, 197, 24, 16, 142, 8, 24, 1, 50, 4, 116, 101, 115,
+ 116, 160, 6, 30, 168, 6, 24,
+ ];
+
+ let want = || mt::principal::UserStageInfo {
+ stage_name: "webhdfs://path/to/stage/files".to_string(),
+ stage_type: mt::principal::StageType::External,
+ stage_params: mt::principal::StageParams {
+ storage: mt::storage::StorageParams::Webhdfs(mt::storage::StorageWebhdfsConfig {
+ endpoint_url: "https://webhdfs.example.com".to_string(),
+ root: "/path/to/stage/files".to_string(),
+ delegation: "".to_string(),
+ }),
+ },
+ file_format_options: mt::principal::FileFormatOptions {
+ format: mt::principal::StageFileFormatType::Json,
+ skip_header: 1024,
+ field_delimiter: "|".to_string(),
+ record_delimiter: "//".to_string(),
+ nan_display: "NaN".to_string(),
+ escape: "".to_string(),
+ compression: mt::principal::StageFileCompression::Bz2,
+ row_tag: "row".to_string(),
+ quote: "".to_string(),
+ name: None,
+ },
+ copy_options: mt::principal::CopyOptions {
+ on_error: mt::principal::OnErrorMode::SkipFileNum(3141),
+ size_limit: 1038,
+ split_size: 0,
+ purge: true,
+ single: false,
+ max_file_size: 0,
+ },
+ comment: "test".to_string(),
+ ..Default::default()
+ };
+ common::test_load_old(func_name!(), user_stage_info_v30.as_slice(), 30, want())?;
+ common::test_pb_from_to(func_name!(), want())?;
+
+ Ok(())
+}
+
#[test]
fn test_user_stage_fs_v22() -> anyhow::Result<()> {
// Encoded data of version 21 of user_stage_fs:
diff --git a/src/meta/proto-conv/tests/it/v030_user_stage.rs b/src/meta/proto-conv/tests/it/v030_user_stage.rs
new file mode 100644
index 0000000000000..8d16804cbc1d6
--- /dev/null
+++ b/src/meta/proto-conv/tests/it/v030_user_stage.rs
@@ -0,0 +1,84 @@
+// Copyright 2023 Datafuse Labs.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use common_meta_app as mt;
+use common_meta_app::storage::StorageParams;
+use common_meta_app::storage::StorageWebhdfsConfig;
+
+use crate::common;
+
+// These bytes are built when a new version in introduced,
+// and are kept for backward compatibility test.
+//
+// *************************************************************
+// * These messages should never be updated, *
+// * only be added when a new version is added, *
+// * or be removed when an old version is no longer supported. *
+// *************************************************************
+//
+// The message bytes are built from the output of `test_user_stage_webhdfs_latest()`
+#[test]
+fn test_decode_v30_user_stage() -> anyhow::Result<()> {
+ // Encoded data of version 30 of common_meta_app::principal::user_stage::UserStageInfo:
+ // It is generated with common::test_pb_from_to().
+ let user_stage_info_v30 = vec![
+ 10, 29, 119, 101, 98, 104, 100, 102, 115, 58, 47, 47, 112, 97, 116, 104, 47, 116, 111, 47,
+ 115, 116, 97, 103, 101, 47, 102, 105, 108, 101, 115, 16, 1, 26, 81, 10, 79, 42, 77, 10, 27,
+ 104, 116, 116, 112, 115, 58, 47, 47, 119, 101, 98, 104, 100, 102, 115, 46, 101, 120, 97,
+ 109, 112, 108, 101, 46, 99, 111, 109, 18, 20, 47, 112, 97, 116, 104, 47, 116, 111, 47, 115,
+ 116, 97, 103, 101, 47, 102, 105, 108, 101, 115, 26, 18, 60, 100, 101, 108, 101, 103, 97,
+ 116, 105, 111, 110, 95, 116, 111, 107, 101, 110, 62, 160, 6, 30, 168, 6, 24, 34, 30, 8, 1,
+ 16, 128, 8, 26, 1, 124, 34, 2, 47, 47, 40, 2, 58, 3, 114, 111, 119, 66, 3, 78, 97, 78, 160,
+ 6, 30, 168, 6, 24, 42, 10, 10, 3, 32, 197, 24, 16, 142, 8, 24, 1, 50, 4, 116, 101, 115,
+ 116, 160, 6, 30, 168, 6, 24,
+ ];
+
+ let want = || mt::principal::UserStageInfo {
+ stage_name: "webhdfs://path/to/stage/files".to_string(),
+ stage_type: mt::principal::StageType::External,
+ stage_params: mt::principal::StageParams {
+ storage: StorageParams::Webhdfs(StorageWebhdfsConfig {
+ endpoint_url: "https://webhdfs.example.com".to_string(),
+ root: "/path/to/stage/files".to_string(),
+ delegation: "".to_string(),
+ }),
+ },
+ file_format_options: mt::principal::FileFormatOptions {
+ format: mt::principal::StageFileFormatType::Json,
+ skip_header: 1024,
+ field_delimiter: "|".to_string(),
+ record_delimiter: "//".to_string(),
+ nan_display: "NaN".to_string(),
+ escape: "".to_string(),
+ compression: mt::principal::StageFileCompression::Bz2,
+ row_tag: "row".to_string(),
+ quote: "".to_string(),
+ name: None,
+ },
+ copy_options: mt::principal::CopyOptions {
+ on_error: mt::principal::OnErrorMode::SkipFileNum(3141),
+ size_limit: 1038,
+ split_size: 0,
+ purge: true,
+ single: false,
+ max_file_size: 0,
+ },
+ comment: "test".to_string(),
+ ..Default::default()
+ };
+ common::test_load_old(func_name!(), user_stage_info_v30.as_slice(), 30, want())?;
+ common::test_pb_from_to(func_name!(), want())?;
+
+ Ok(())
+}
diff --git a/src/meta/protos/proto/config.proto b/src/meta/protos/proto/config.proto
index 76e4184aee602..b60de63678183 100644
--- a/src/meta/protos/proto/config.proto
+++ b/src/meta/protos/proto/config.proto
@@ -61,3 +61,15 @@ message OssStorageConfig {
string access_key_id = 4;
string access_key_secret = 5;
}
+
+message WebhdfsStorageConfig {
+ uint64 version = 100;
+ uint64 min_reader_ver = 101;
+
+ string endpoint_url = 1;
+ string root = 2;
+ string delegation = 3;
+
+ string username = 4; // reserved for future use
+ string password = 5; // reserved for future use
+}
diff --git a/src/meta/protos/proto/user.proto b/src/meta/protos/proto/user.proto
index 2aea78729d73b..07478430f12a5 100644
--- a/src/meta/protos/proto/user.proto
+++ b/src/meta/protos/proto/user.proto
@@ -136,6 +136,7 @@ message UserStageInfo {
FsStorageConfig fs = 2;
GcsStorageConfig gcs = 3;
OssStorageConfig oss = 4;
+ WebhdfsStorageConfig webhdfs = 5;
}
}
diff --git a/src/meta/raft-store/Cargo.toml b/src/meta/raft-store/Cargo.toml
index 4f4833d6112ba..45222dd50c7cc 100644
--- a/src/meta/raft-store/Cargo.toml
+++ b/src/meta/raft-store/Cargo.toml
@@ -37,7 +37,6 @@ maplit = "1.0.2"
num = "0.4.0"
once_cell = "1.15.0"
serde = { workspace = true }
-serde_json = { workspace = true }
tracing = "0.1.36"
[dev-dependencies]
diff --git a/src/meta/raft-store/src/lib.rs b/src/meta/raft-store/src/lib.rs
index 125a6e4354f07..12301f35f1e49 100644
--- a/src/meta/raft-store/src/lib.rs
+++ b/src/meta/raft-store/src/lib.rs
@@ -19,5 +19,3 @@ pub mod key_spaces;
pub mod log;
pub mod state;
pub mod state_machine;
-
-pub mod applied_state;
diff --git a/src/meta/raft-store/src/state_machine/client_last_resp.rs b/src/meta/raft-store/src/state_machine/client_last_resp.rs
index f0e743a216c36..5a331e5e1dba4 100644
--- a/src/meta/raft-store/src/state_machine/client_last_resp.rs
+++ b/src/meta/raft-store/src/state_machine/client_last_resp.rs
@@ -12,11 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+use common_meta_types::AppliedState;
use serde::Deserialize;
use serde::Serialize;
-use crate::applied_state::AppliedState;
-
/// Client last response that is stored in SledTree
/// raft state: A mapping of client serial IDs to their state info:
/// (serial, RaftResponse)
diff --git a/src/meta/raft-store/src/state_machine/sm.rs b/src/meta/raft-store/src/state_machine/sm.rs
index a3b7cc0940ccd..621626d44d4b2 100644
--- a/src/meta/raft-store/src/state_machine/sm.rs
+++ b/src/meta/raft-store/src/state_machine/sm.rs
@@ -34,6 +34,7 @@ use common_meta_types::protobuf as pb;
use common_meta_types::txn_condition;
use common_meta_types::txn_op;
use common_meta_types::txn_op_response;
+use common_meta_types::AppliedState;
use common_meta_types::Change;
use common_meta_types::Cmd;
use common_meta_types::ConditionResult;
@@ -69,7 +70,6 @@ use tracing::debug;
use tracing::error;
use tracing::info;
-use crate::applied_state::AppliedState;
use crate::config::RaftConfig;
use crate::key_spaces::ClientLastResps;
use crate::key_spaces::Expire;
diff --git a/src/meta/raft-store/src/state_machine/sm_kv_api_impl.rs b/src/meta/raft-store/src/state_machine/sm_kv_api_impl.rs
index 07b69fc3fee99..92d0cbefea034 100644
--- a/src/meta/raft-store/src/state_machine/sm_kv_api_impl.rs
+++ b/src/meta/raft-store/src/state_machine/sm_kv_api_impl.rs
@@ -17,6 +17,7 @@ use common_meta_kvapi::kvapi::GetKVReply;
use common_meta_kvapi::kvapi::MGetKVReply;
use common_meta_kvapi::kvapi::UpsertKVReply;
use common_meta_kvapi::kvapi::UpsertKVReq;
+use common_meta_types::AppliedState;
use common_meta_types::Cmd;
use common_meta_types::MetaError;
use common_meta_types::SeqV;
@@ -25,7 +26,6 @@ use common_meta_types::TxnRequest;
use common_meta_types::UpsertKV;
use tracing::debug;
-use crate::applied_state::AppliedState;
use crate::state_machine::StateMachine;
#[async_trait::async_trait]
diff --git a/src/meta/raft-store/tests/it/state_machine/mod.rs b/src/meta/raft-store/tests/it/state_machine/mod.rs
index 3508543842af4..ad19caececdc7 100644
--- a/src/meta/raft-store/tests/it/state_machine/mod.rs
+++ b/src/meta/raft-store/tests/it/state_machine/mod.rs
@@ -17,9 +17,9 @@ use std::time::UNIX_EPOCH;
use common_base::base::tokio;
use common_meta_kvapi::kvapi::KVApi;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_raft_store::state_machine::StateMachine;
use common_meta_sled_store::openraft;
+use common_meta_types::AppliedState;
use common_meta_types::Change;
use common_meta_types::Cmd;
use common_meta_types::Endpoint;
diff --git a/src/meta/service/src/message.rs b/src/meta/service/src/message.rs
index 3bdecfa0ec7a1..db551c3087dc1 100644
--- a/src/meta/service/src/message.rs
+++ b/src/meta/service/src/message.rs
@@ -18,9 +18,9 @@ use common_meta_kvapi::kvapi::ListKVReply;
use common_meta_kvapi::kvapi::ListKVReq;
use common_meta_kvapi::kvapi::MGetKVReply;
use common_meta_kvapi::kvapi::MGetKVReq;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_sled_store::openraft::NodeId;
use common_meta_types::protobuf::RaftRequest;
+use common_meta_types::AppliedState;
use common_meta_types::Endpoint;
use common_meta_types::LogEntry;
diff --git a/src/meta/service/src/meta_service/meta_leader.rs b/src/meta/service/src/meta_service/meta_leader.rs
index 1a6a2c3aea218..c95310905b48a 100644
--- a/src/meta/service/src/meta_service/meta_leader.rs
+++ b/src/meta/service/src/meta_service/meta_leader.rs
@@ -16,10 +16,10 @@ use std::sync::Arc;
use common_base::base::tokio::sync::RwLockReadGuard;
use common_meta_kvapi::kvapi::KVApi;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_raft_store::state_machine::StateMachine;
use common_meta_sled_store::openraft::error::RemoveLearnerError;
use common_meta_stoerr::MetaStorageError;
+use common_meta_types::AppliedState;
use common_meta_types::Cmd;
use common_meta_types::LogEntry;
use common_meta_types::MetaDataError;
diff --git a/src/meta/service/src/meta_service/meta_node_kv_api_impl.rs b/src/meta/service/src/meta_service/meta_node_kv_api_impl.rs
index a0cf2d5d39ab6..b9d9953c8aa22 100644
--- a/src/meta/service/src/meta_service/meta_node_kv_api_impl.rs
+++ b/src/meta/service/src/meta_service/meta_node_kv_api_impl.rs
@@ -22,7 +22,7 @@ use common_meta_kvapi::kvapi::MGetKVReply;
use common_meta_kvapi::kvapi::MGetKVReq;
use common_meta_kvapi::kvapi::UpsertKVReply;
use common_meta_kvapi::kvapi::UpsertKVReq;
-use common_meta_raft_store::applied_state::AppliedState;
+use common_meta_types::AppliedState;
use common_meta_types::Cmd;
use common_meta_types::LogEntry;
use common_meta_types::MetaAPIError;
diff --git a/src/meta/service/src/meta_service/raftmeta.rs b/src/meta/service/src/meta_service/raftmeta.rs
index 08403be13d732..ae9cb42cc273d 100644
--- a/src/meta/service/src/meta_service/raftmeta.rs
+++ b/src/meta/service/src/meta_service/raftmeta.rs
@@ -29,7 +29,6 @@ use common_base::base::tokio::time::Instant;
use common_grpc::ConnectionFactory;
use common_grpc::DNSResolver;
use common_meta_client::reply_to_api_result;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_raft_store::config::RaftConfig;
use common_meta_raft_store::key_spaces::GenericKV;
use common_meta_sled_store::openraft;
@@ -41,6 +40,7 @@ use common_meta_stoerr::MetaStorageError;
use common_meta_types::protobuf::raft_service_client::RaftServiceClient;
use common_meta_types::protobuf::raft_service_server::RaftServiceServer;
use common_meta_types::protobuf::WatchRequest;
+use common_meta_types::AppliedState;
use common_meta_types::Cmd;
use common_meta_types::ConnectionError;
use common_meta_types::Endpoint;
diff --git a/src/meta/service/src/store/mod.rs b/src/meta/service/src/store/mod.rs
index 62e9210b68afb..ce55c66d03bfe 100644
--- a/src/meta/service/src/store/mod.rs
+++ b/src/meta/service/src/store/mod.rs
@@ -15,8 +15,8 @@
mod store_bare;
mod to_storage_error;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_sled_store::openraft::StoreExt;
+use common_meta_types::AppliedState;
use common_meta_types::LogEntry;
pub use store_bare::RaftStoreBare;
pub use to_storage_error::ToStorageError;
diff --git a/src/meta/service/src/store/store_bare.rs b/src/meta/service/src/store/store_bare.rs
index da6bca334b693..3db329aec7cf4 100644
--- a/src/meta/service/src/store/store_bare.rs
+++ b/src/meta/service/src/store/store_bare.rs
@@ -20,7 +20,6 @@ use std::ops::RangeBounds;
use anyerror::AnyError;
use common_base::base::tokio::sync::RwLock;
use common_base::base::tokio::sync::RwLockWriteGuard;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_raft_store::config::RaftConfig;
use common_meta_raft_store::log::RaftLog;
use common_meta_raft_store::state::RaftState;
@@ -36,6 +35,7 @@ use common_meta_sled_store::openraft::ErrorVerb;
use common_meta_sled_store::openraft::Membership;
use common_meta_sled_store::openraft::StateMachineChanges;
use common_meta_stoerr::MetaStorageError;
+use common_meta_types::AppliedState;
use common_meta_types::Endpoint;
use common_meta_types::LogEntry;
use common_meta_types::MetaError;
diff --git a/src/meta/service/tests/it/store.rs b/src/meta/service/tests/it/store.rs
index 570e3149b54e1..2512e21199dda 100644
--- a/src/meta/service/tests/it/store.rs
+++ b/src/meta/service/tests/it/store.rs
@@ -16,7 +16,6 @@ use std::sync::Arc;
use std::sync::Mutex;
use common_base::base::tokio;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_raft_store::state_machine::testing::pretty_snapshot;
use common_meta_raft_store::state_machine::testing::snapshot_logs;
use common_meta_raft_store::state_machine::SerializableSnapshot;
@@ -30,6 +29,7 @@ use common_meta_sled_store::openraft::LogId;
use common_meta_sled_store::openraft::Membership;
use common_meta_sled_store::openraft::RaftStorage;
use common_meta_sled_store::openraft::StorageHelper;
+use common_meta_types::AppliedState;
use common_meta_types::LogEntry;
use databend_meta::init_meta_ut;
use databend_meta::store::RaftStoreBare;
diff --git a/src/meta/service/tests/it/tests/meta_node.rs b/src/meta/service/tests/it/tests/meta_node.rs
index b6b5730b5e202..268a300ef866e 100644
--- a/src/meta/service/tests/it/tests/meta_node.rs
+++ b/src/meta/service/tests/it/tests/meta_node.rs
@@ -18,9 +18,9 @@ use std::collections::BTreeSet;
use std::sync::Arc;
use std::time::Duration;
-use common_meta_raft_store::applied_state::AppliedState;
use common_meta_sled_store::openraft::NodeId;
use common_meta_sled_store::openraft::State;
+use common_meta_types::AppliedState;
use common_meta_types::Node;
use databend_meta::meta_service::MetaNode;
use databend_meta::Opened;
diff --git a/src/meta/raft-store/src/applied_state.rs b/src/meta/types/src/applied_state.rs
similarity index 96%
rename from src/meta/raft-store/src/applied_state.rs
rename to src/meta/types/src/applied_state.rs
index cf39157ea83f3..c136134d78bfd 100644
--- a/src/meta/raft-store/src/applied_state.rs
+++ b/src/meta/types/src/applied_state.rs
@@ -15,10 +15,10 @@
use std::fmt;
use std::fmt::Formatter;
-use common_meta_types::protobuf::RaftReply;
-use common_meta_types::Change;
-use common_meta_types::Node;
-use common_meta_types::TxnReply;
+use crate::protobuf::RaftReply;
+use crate::Change;
+use crate::Node;
+use crate::TxnReply;
/// The state of an applied raft log.
/// Normally it includes two fields: the state before applying and the state after applying the log.
diff --git a/src/meta/types/src/lib.rs b/src/meta/types/src/lib.rs
index bc940ae42ec7a..45a9b1ff66148 100644
--- a/src/meta/types/src/lib.rs
+++ b/src/meta/types/src/lib.rs
@@ -18,6 +18,7 @@
//! This crate defines data types used in meta data storage service.
+mod applied_state;
mod change;
mod cluster;
mod cmd;
@@ -48,6 +49,7 @@ pub mod protobuf {
pub const FILE_DESCRIPTOR_SET: &[u8] = tonic::include_file_descriptor_set!("meta_descriptor");
}
+pub use applied_state::AppliedState;
pub use change::Change;
pub use cluster::Node;
pub use cluster::NodeInfo;
diff --git a/src/query/ast/src/ast/format/syntax/query.rs b/src/query/ast/src/ast/format/syntax/query.rs
index 2f597efa19828..e4bbec89bd2ce 100644
--- a/src/query/ast/src/ast/format/syntax/query.rs
+++ b/src/query/ast/src/ast/format/syntax/query.rs
@@ -334,19 +334,7 @@ pub(crate) fn pretty_table(table: TableReference) -> RcDoc<'static> {
options,
alias,
} => RcDoc::text(location.to_string())
- .append(if let Some(files) = options.files {
- let files = files.join(",");
- let files = format!("FILES {}", files);
- RcDoc::text(files)
- } else {
- RcDoc::nil()
- })
- .append(if let Some(pattern) = options.pattern {
- let pattern = format!("Pattern {pattern}");
- RcDoc::text(pattern)
- } else {
- RcDoc::nil()
- })
+ .append(options.to_string())
.append(if let Some(a) = alias {
RcDoc::text(format!(" AS {a}"))
} else {
diff --git a/src/query/ast/src/ast/query.rs b/src/query/ast/src/ast/query.rs
index ce0c6ad562802..f5c56fdae7a30 100644
--- a/src/query/ast/src/ast/query.rs
+++ b/src/query/ast/src/ast/query.rs
@@ -372,13 +372,7 @@ impl Display for TableReference {
alias,
} => {
write!(f, "{location}")?;
- if let Some(files) = &options.files {
- let files = files.join(",");
- write!(f, " FILES {files}")?;
- }
- if let Some(pattern) = &options.pattern {
- write!(f, " PATTERN {pattern}")?;
- }
+ write!(f, "{options}")?;
if let Some(alias) = alias {
write!(f, " AS {alias}")?;
}
diff --git a/src/query/ast/src/ast/statements/copy.rs b/src/query/ast/src/ast/statements/copy.rs
index 5c8e7573e9871..2da4e32ed97ee 100644
--- a/src/query/ast/src/ast/statements/copy.rs
+++ b/src/query/ast/src/ast/statements/copy.rs
@@ -348,7 +348,7 @@ impl Display for FileLocation {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
FileLocation::Uri(loc) => {
- write!(f, "{}", loc)
+ write!(f, "'{}'", loc)
}
FileLocation::Stage(loc) => {
write!(f, "{}", loc)
diff --git a/src/query/ast/src/ast/statements/stage.rs b/src/query/ast/src/ast/statements/stage.rs
index d0e347c65f524..b425b475d2ac5 100644
--- a/src/query/ast/src/ast/statements/stage.rs
+++ b/src/query/ast/src/ast/statements/stage.rs
@@ -90,6 +90,58 @@ pub struct SelectStageOptions {
pub connection: BTreeMap,
}
+// SELECT FROM
+// {@[/] | ''} [(
+// [ PARTTERN => '']
+// [ FILE_FORMAT => '']
+// [ FILES => ( 'file_name' [ , 'file_name' ... ] ) ]
+// [ ENDPOINT_URL => <'url'> ]
+// [ AWS_KEY_ID => <'aws_key_id'> ]
+// [ AWS_KEY_SECRET => <'aws_key_secret'> ]
+// [ ACCESS_KEY_ID => <'access_key_id'> ]
+// [ ACCESS_KEY_SECRET => <'access_key_secret'> ]
+// [ SECRET_ACCESS_KEY => <'secret_access_key'> ]
+// [ SESSION_TOKEN => <'session_token'> ]
+// [ REGION => <'region'> ]
+// [ ENABLE_VIRTUAL_HOST_STYLE => true|false ]
+// )]
+impl Display for SelectStageOptions {
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
+ write!(f, " (")?;
+
+ let mut output: Vec = vec![];
+ if let Some(files) = self.files.clone() {
+ let files = files
+ .iter()
+ .map(|x| format!("'{}'", x))
+ .collect::>();
+ let files = files.join(",");
+ let files = format!("FILES => ({})", files);
+ output.push(files);
+ }
+
+ if let Some(file_format) = self.file_format.clone() {
+ let file_format = format!("FILE_FORMAT => '{}'", file_format);
+ output.push(file_format);
+ }
+
+ if let Some(pattern) = self.pattern.clone() {
+ let pattern = format!("PATTERN => '{}'", pattern);
+ output.push(pattern);
+ }
+
+ if !self.connection.is_empty() {
+ for (k, v) in self.connection.iter() {
+ output.push(format!(" {} => '{}'", k, v));
+ }
+ }
+
+ let output = output.join(",");
+ write!(f, "{output})")?;
+ Ok(())
+ }
+}
+
impl SelectStageOptions {
pub fn from(opts: Vec) -> Self {
let mut options: SelectStageOptions = Default::default();
diff --git a/src/query/ast/src/parser/expr.rs b/src/query/ast/src/parser/expr.rs
index edc2157e7901d..7caab997bba91 100644
--- a/src/query/ast/src/parser/expr.rs
+++ b/src/query/ast/src/parser/expr.rs
@@ -326,8 +326,8 @@ impl<'a, I: Iterator>> PrattParser for ExprP
ExprElement::UnaryOp { op } => match op {
UnaryOperator::Not => Affix::Prefix(Precedence(NOT_PREC)),
- UnaryOperator::Plus => Affix::Prefix(Precedence(30)),
- UnaryOperator::Minus => Affix::Prefix(Precedence(30)),
+ UnaryOperator::Plus => Affix::Prefix(Precedence(50)),
+ UnaryOperator::Minus => Affix::Prefix(Precedence(50)),
},
ExprElement::BinaryOp { op } => match op {
BinaryOperator::Or => Affix::Infix(Precedence(5), Associativity::Left),
@@ -362,7 +362,7 @@ impl<'a, I: Iterator>> PrattParser for ExprP
BinaryOperator::Modulo => Affix::Infix(Precedence(40), Associativity::Left),
BinaryOperator::StringConcat => Affix::Infix(Precedence(40), Associativity::Left),
},
- ExprElement::PgCast { .. } => Affix::Postfix(Precedence(50)),
+ ExprElement::PgCast { .. } => Affix::Postfix(Precedence(60)),
_ => Affix::Nilfix,
};
Ok(affix)
diff --git a/src/query/ast/src/parser/stage.rs b/src/query/ast/src/parser/stage.rs
index 51e29a93060a0..c21eae3dd9107 100644
--- a/src/query/ast/src/parser/stage.rs
+++ b/src/query/ast/src/parser/stage.rs
@@ -55,6 +55,8 @@ fn connection_opt(sep: &'static str) -> impl FnMut(Input) -> IResult<(String, St
| SECRET_ACCESS_KEY
| SESSION_TOKEN
| REGION
+ | HTTPS
+ | DELEGATION
| ENABLE_VIRTUAL_HOST_STYLE)
~ #sep1 ~ #literal_string
},
diff --git a/src/query/ast/src/parser/token.rs b/src/query/ast/src/parser/token.rs
index 478963b42bb03..eaa20bcf2e63c 100644
--- a/src/query/ast/src/parser/token.rs
+++ b/src/query/ast/src/parser/token.rs
@@ -363,6 +363,8 @@ pub enum TokenKind {
DEFAULT,
#[token("DEFLATE", ignore(ascii_case))]
DEFLATE,
+ #[token("DELEGATION", ignore(ascii_case))]
+ DELEGATION, // delegation token, used in webhdfs
#[token("DELETE", ignore(ascii_case))]
DELETE,
#[token("DESC", ignore(ascii_case))]
@@ -475,6 +477,8 @@ pub enum TokenKind {
HIVE,
#[token("HOUR", ignore(ascii_case))]
HOUR,
+ #[token("HTTPS", ignore(ascii_case))]
+ HTTPS,
#[token("ICEBERG", ignore(ascii_case))]
ICEBERG,
#[token("INTERSECT", ignore(ascii_case))]
diff --git a/src/query/ast/tests/it/testdata/expr.txt b/src/query/ast/tests/it/testdata/expr.txt
index f62369076704c..aa2d3a0a23946 100644
--- a/src/query/ast/tests/it/testdata/expr.txt
+++ b/src/query/ast/tests/it/testdata/expr.txt
@@ -730,39 +730,39 @@ FunctionCall {
---------- Input ----------
- - + + - 1 + + - 2
---------- Output ---------
-(- (- (+ (+ (- (1 + (+ (- 2))))))))
+((- (- (+ (+ (- 1))))) + (+ (- 2)))
---------- AST ------------
-UnaryOp {
+BinaryOp {
span: Some(
- 0..1,
+ 12..13,
),
- op: Minus,
- expr: UnaryOp {
+ op: Plus,
+ left: UnaryOp {
span: Some(
- 2..3,
+ 0..1,
),
op: Minus,
expr: UnaryOp {
span: Some(
- 4..5,
+ 2..3,
),
- op: Plus,
+ op: Minus,
expr: UnaryOp {
span: Some(
- 6..7,
+ 4..5,
),
op: Plus,
expr: UnaryOp {
span: Some(
- 8..9,
+ 6..7,
),
- op: Minus,
- expr: BinaryOp {
+ op: Plus,
+ expr: UnaryOp {
span: Some(
- 12..13,
+ 8..9,
),
- op: Plus,
- left: Literal {
+ op: Minus,
+ expr: Literal {
span: Some(
10..11,
),
@@ -770,31 +770,31 @@ UnaryOp {
1,
),
},
- right: UnaryOp {
- span: Some(
- 14..15,
- ),
- op: Plus,
- expr: UnaryOp {
- span: Some(
- 16..17,
- ),
- op: Minus,
- expr: Literal {
- span: Some(
- 18..19,
- ),
- lit: Integer(
- 2,
- ),
- },
- },
- },
},
},
},
},
},
+ right: UnaryOp {
+ span: Some(
+ 14..15,
+ ),
+ op: Plus,
+ expr: UnaryOp {
+ span: Some(
+ 16..17,
+ ),
+ op: Minus,
+ expr: Literal {
+ span: Some(
+ 18..19,
+ ),
+ lit: Integer(
+ 2,
+ ),
+ },
+ },
+ },
}
diff --git a/src/query/config/src/config.rs b/src/query/config/src/config.rs
index 8c5dbcbcb8796..832c4303b559e 100644
--- a/src/query/config/src/config.rs
+++ b/src/query/config/src/config.rs
@@ -262,6 +262,10 @@ impl From for StorageConfig {
storage_num_cpus: inner.num_cpus,
storage_type: "".to_string(),
allow_insecure: inner.allow_insecure,
+ // use default for each config instead of using `..Default::default`
+ // using `..Default::default` is calling `Self::default`
+ // and `Self::default` relies on `InnerStorage::into()`
+ // this will lead to a stack overflow
fs: Default::default(),
gcs: Default::default(),
s3: Default::default(),
diff --git a/src/query/expression/Cargo.toml b/src/query/expression/Cargo.toml
index e1c982533cd55..439c68f34ab1c 100755
--- a/src/query/expression/Cargo.toml
+++ b/src/query/expression/Cargo.toml
@@ -39,7 +39,6 @@ micromarshal = "0.2.1"
num-traits = "0.2.15"
once_cell = "1.15.0"
ordered-float = { workspace = true, features = ["serde", "rand"] }
-primitive-types = "0.12.0"
rand = { version = "0.8.5", features = ["small_rng"] }
rust_decimal = "1.26"
serde = { workspace = true }
diff --git a/src/query/expression/src/block.rs b/src/query/expression/src/block.rs
index c231fc3592c7f..84980f7be322f 100644
--- a/src/query/expression/src/block.rs
+++ b/src/query/expression/src/block.rs
@@ -53,9 +53,8 @@ pub struct BlockEntry {
}
#[typetag::serde(tag = "type")]
-pub trait BlockMetaInfo: Debug + Send + Sync {
+pub trait BlockMetaInfo: Debug + Send + Sync + 'static {
fn as_any(&self) -> &dyn Any;
- fn as_mut_any(&mut self) -> &mut dyn Any;
#[allow(clippy::borrowed_box)]
fn equals(&self, info: &Box) -> bool;
@@ -63,6 +62,38 @@ pub trait BlockMetaInfo: Debug + Send + Sync {
fn clone_self(&self) -> Box;
}
+pub trait BlockMetaInfoDowncast: Sized {
+ fn downcast_from(boxed: BlockMetaInfoPtr) -> Option;
+
+ fn downcast_ref_from(boxed: &BlockMetaInfoPtr) -> Option<&Self>;
+}
+
+impl BlockMetaInfoDowncast for T {
+ fn downcast_from(boxed: BlockMetaInfoPtr) -> Option {
+ if boxed.as_any().is::() {
+ unsafe {
+ // SAFETY: `is` ensures this type cast is correct
+ let raw_ptr = Box::into_raw(boxed) as *const dyn BlockMetaInfo;
+ return Some(std::ptr::read(raw_ptr as *const Self));
+ }
+ }
+
+ None
+ }
+
+ fn downcast_ref_from(boxed: &BlockMetaInfoPtr) -> Option<&Self> {
+ if boxed.as_any().is::() {
+ unsafe {
+ // SAFETY: `is` ensures this type cast is correct
+ let unboxed = boxed.as_ref();
+ return Some(&*(unboxed as *const dyn BlockMetaInfo as *const Self));
+ }
+ }
+
+ None
+ }
+}
+
impl DataBlock {
#[inline]
pub fn new(columns: Vec, num_rows: usize) -> Self {
diff --git a/src/query/expression/src/deserializations/decimal.rs b/src/query/expression/src/deserializations/decimal.rs
index ff321a8a7f3ed..1d93346e474a0 100644
--- a/src/query/expression/src/deserializations/decimal.rs
+++ b/src/query/expression/src/deserializations/decimal.rs
@@ -85,8 +85,10 @@ impl TypeDeserializer for DecimalDeserializer {
// See GroupHash.rs for StringColumn
#[allow(clippy::uninit_vec)]
- fn de_binary(&mut self, _reader: &mut &[u8], _format: &FormatSettings) -> Result<()> {
- todo!()
+ fn de_binary(&mut self, reader: &mut &[u8], _format: &FormatSettings) -> Result<()> {
+ let t: T = T::de_binary(reader);
+ self.values.push(t);
+ Ok(())
}
fn de_default(&mut self) {
@@ -95,12 +97,17 @@ impl TypeDeserializer for DecimalDeserializer {
fn de_fixed_binary_batch(
&mut self,
- _reader: &[u8],
- _step: usize,
- _rows: usize,
+ reader: &[u8],
+ step: usize,
+ rows: usize,
_format: &FormatSettings,
) -> Result<()> {
- todo!()
+ for row in 0..rows {
+ let mut row_reader = &reader[step * row..];
+ let value: T = T::de_binary(&mut row_reader);
+ self.values.push(value);
+ }
+ Ok(())
}
fn de_json(&mut self, value: &serde_json::Value, _format: &FormatSettings) -> Result<()> {
diff --git a/src/query/expression/src/evaluator.rs b/src/query/expression/src/evaluator.rs
index e97dcf5366d34..25cd924b2becd 100644
--- a/src/query/expression/src/evaluator.rs
+++ b/src/query/expression/src/evaluator.rs
@@ -13,8 +13,6 @@
// limitations under the License.
use std::collections::HashMap;
-#[cfg(debug_assertions)]
-use std::sync::Mutex;
use common_arrow::arrow::bitmap;
use common_exception::ErrorCode;
@@ -168,30 +166,31 @@ impl<'a> Evaluator<'a> {
}
};
- #[cfg(debug_assertions)]
- if result.is_err() {
- static RECURSING: Mutex = Mutex::new(false);
- if !*RECURSING.lock().unwrap() {
- *RECURSING.lock().unwrap() = true;
- assert_eq!(
- ConstantFolder::fold_with_domain(
- expr,
- self.input_columns
- .domains()
- .into_iter()
- .enumerate()
- .collect(),
- self.func_ctx,
- self.fn_registry
- )
- .1,
- None,
- "domain calculation should not return any domain for expressions that are possible to fail"
- );
- *RECURSING.lock().unwrap() = false;
- }
- }
-
+ // We can't call this in debug mode, because it will cause infinite recursion.
+ // Eg: select 3.2::Decimal(10, 2)::Int32;
+ // #[cfg(debug_assertions)]
+ // if result.is_err() {
+ // static RECURSING: Mutex = Mutex::new(false);
+ // if !*RECURSING.lock().unwrap() {
+ // *RECURSING.lock().unwrap() = true;
+ // assert_eq!(
+ // ConstantFolder::fold_with_domain(
+ // expr,
+ // self.input_columns
+ // .domains()
+ // .into_iter()
+ // .enumerate()
+ // .collect(),
+ // self.func_ctx,
+ // self.fn_registry
+ // )
+ // .1,
+ // None,
+ // "domain calculation should not return any domain for expressions that are possible to fail"
+ // );
+ // *RECURSING.lock().unwrap() = false;
+ // }
+ // }
result
}
diff --git a/src/query/expression/src/kernels/group_by.rs b/src/query/expression/src/kernels/group_by.rs
index 1f6ef3ce9ec1c..cab915bc66306 100644
--- a/src/query/expression/src/kernels/group_by.rs
+++ b/src/query/expression/src/kernels/group_by.rs
@@ -25,7 +25,6 @@ use crate::types::DataType;
use crate::DataBlock;
use crate::HashMethodKeysU128;
use crate::HashMethodKeysU256;
-use crate::HashMethodKeysU512;
impl DataBlock {
pub fn choose_hash_method(chunk: &DataBlock, indices: &[usize]) -> Result {
@@ -55,7 +54,10 @@ impl DataBlock {
for typ in hash_key_types {
let not_null_type = typ.remove_nullable();
- if not_null_type.is_numeric() || not_null_type.is_date_or_date_time() {
+ if not_null_type.is_numeric()
+ || not_null_type.is_date_or_date_time()
+ || not_null_type.is_decimal()
+ {
group_key_len += not_null_type.numeric_byte_size().unwrap();
// extra one byte for null flag
@@ -74,7 +76,6 @@ impl DataBlock {
5..=8 => Ok(HashMethodKind::KeysU64(HashMethodKeysU64::default())),
9..=16 => Ok(HashMethodKind::KeysU128(HashMethodKeysU128::default())),
17..=32 => Ok(HashMethodKind::KeysU256(HashMethodKeysU256::default())),
- 33..=64 => Ok(HashMethodKind::KeysU512(HashMethodKeysU512::default())),
_ => Ok(HashMethodKind::Serializer(HashMethodSerializer::default())),
}
}
diff --git a/src/query/expression/src/kernels/group_by_hash.rs b/src/query/expression/src/kernels/group_by_hash.rs
index 26c7d08cf801b..6352acbec28ae 100644
--- a/src/query/expression/src/kernels/group_by_hash.rs
+++ b/src/query/expression/src/kernels/group_by_hash.rs
@@ -24,20 +24,25 @@ use common_exception::Result;
use common_hashtable::FastHash;
use common_io::prelude::BinaryWrite;
use common_io::prelude::FormatSettings;
+use ethnum::i256;
+use ethnum::u256;
+use ethnum::U256;
use micromarshal::Marshal;
-use primitive_types::U256;
-use primitive_types::U512;
use crate::types::boolean::BooleanType;
+use crate::types::decimal::Decimal;
+use crate::types::decimal::DecimalColumn;
use crate::types::nullable::NullableColumn;
use crate::types::number::Number;
use crate::types::number::NumberColumn;
use crate::types::string::StringColumnBuilder;
use crate::types::string::StringIterator;
use crate::types::DataType;
+use crate::types::DecimalDataType;
use crate::types::NumberDataType;
use crate::types::NumberType;
use crate::types::ValueType;
+use crate::with_decimal_mapped_type;
use crate::with_integer_mapped_type;
use crate::with_number_mapped_type;
use crate::Column;
@@ -46,9 +51,8 @@ use crate::TypeDeserializer;
#[derive(Debug)]
pub enum KeysState {
Column(Column),
- U128(Vec),
- U256(Vec),
- U512(Vec),
+ U128(Buffer),
+ U256(Buffer),
}
pub trait HashMethod: Clone + Sync + Send + 'static {
@@ -73,8 +77,7 @@ pub type HashMethodKeysU16 = HashMethodFixedKeys;
pub type HashMethodKeysU32 = HashMethodFixedKeys;
pub type HashMethodKeysU64 = HashMethodFixedKeys;
pub type HashMethodKeysU128 = HashMethodFixedKeys;
-pub type HashMethodKeysU256 = HashMethodFixedKeys;
-pub type HashMethodKeysU512 = HashMethodFixedKeys;
+pub type HashMethodKeysU256 = HashMethodFixedKeys;
/// These methods are `generic` method to generate hash key,
/// that is the 'numeric' or 'binary` representation of each column value as hash key.
@@ -88,7 +91,6 @@ pub enum HashMethodKind {
KeysU64(HashMethodKeysU64),
KeysU128(HashMethodKeysU128),
KeysU256(HashMethodKeysU256),
- KeysU512(HashMethodKeysU512),
}
#[macro_export]
@@ -96,7 +98,7 @@ macro_rules! with_hash_method {
( | $t:tt | $($tail:tt)* ) => {
match_template::match_template! {
$t = [Serializer, SingleString, KeysU8, KeysU16,
- KeysU32, KeysU64, KeysU128, KeysU256, KeysU512],
+ KeysU32, KeysU64, KeysU128, KeysU256],
$($tail)*
}
}
@@ -115,7 +117,6 @@ macro_rules! with_mappedhash_method {
KeysU64 => HashMethodKeysU64,
KeysU128 => HashMethodKeysU128,
KeysU256 => HashMethodKeysU256,
- KeysU512 => HashMethodKeysU512
],
$($tail)*
}
@@ -137,9 +138,12 @@ impl HashMethodKind {
HashMethodKind::KeysU16(_) => DataType::Number(NumberDataType::UInt16),
HashMethodKind::KeysU32(_) => DataType::Number(NumberDataType::UInt32),
HashMethodKind::KeysU64(_) => DataType::Number(NumberDataType::UInt64),
- HashMethodKind::KeysU128(_)
- | HashMethodKind::KeysU256(_)
- | HashMethodKind::KeysU512(_) => DataType::String,
+ HashMethodKind::KeysU128(_) => {
+ DataType::Decimal(DecimalDataType::Decimal128(i128::default_decimal_size()))
+ }
+ HashMethodKind::KeysU256(_) => {
+ DataType::Decimal(DecimalDataType::Decimal256(i256::default_decimal_size()))
+ }
}
}
}
@@ -275,7 +279,7 @@ where T: Clone
debug_assert!(!keys.is_empty());
// faster path for single signed/unsigned integer to column
- if group_items.len() == 1 && group_items[0].1.is_numeric() {
+ if group_items.len() == 1 {
if let DataType::Number(ty) = group_items[0].1 {
with_integer_mapped_type!(|NUM_TYPE| match ty {
NumberDataType::NUM_TYPE => {
@@ -287,6 +291,19 @@ where T: Clone
_ => {}
})
}
+
+ if matches!(group_items[0].1, DataType::Decimal(_)) {
+ with_decimal_mapped_type!(|DECIMAL_TYPE| match group_items[0].1 {
+ DataType::Decimal(DecimalDataType::DECIMAL_TYPE(size)) => {
+ let buffer: Buffer = keys.into();
+ let col = unsafe {
+ std::mem::transmute::, Buffer>(buffer)
+ };
+ return Ok(vec![DECIMAL_TYPE::upcast_column(col, size)]);
+ }
+ _ => {}
+ })
+ }
}
let mut keys = keys;
@@ -444,8 +461,25 @@ macro_rules! impl_hash_method_fixed_large_keys {
group_columns: &[(Column, DataType)],
rows: usize,
) -> Result {
+ // faster path for single fixed decimal keys
+ if group_columns.len() == 1 {
+ if group_columns[0].1.is_decimal() {
+ with_decimal_mapped_type!(|DECIMAL_TYPE| match &group_columns[0].0 {
+ Column::Decimal(DecimalColumn::DECIMAL_TYPE(c, _)) => {
+ let buffer = unsafe {
+ std::mem::transmute::, Buffer<$ty>>(
+ c.clone(),
+ )
+ };
+ return Ok(KeysState::$name(buffer));
+ }
+ _ => {}
+ })
+ }
+ }
+
let keys = self.build_keys_vec(group_columns, rows)?;
- Ok(KeysState::$name(keys))
+ Ok(KeysState::$name(keys.into()))
}
fn build_keys_iter<'a>(
@@ -463,7 +497,6 @@ macro_rules! impl_hash_method_fixed_large_keys {
impl_hash_method_fixed_large_keys! {u128, U128}
impl_hash_method_fixed_large_keys! {U256, U256}
-impl_hash_method_fixed_large_keys! {U512, U512}
#[inline]
fn build(
@@ -502,7 +535,13 @@ pub fn serialize_column_binary(column: &Column, row: usize, vec: &mut Vec) {
Column::String(v) => {
BinaryWrite::write_binary(vec, unsafe { v.index_unchecked(row) }).unwrap()
}
- Column::Decimal(_) => unreachable!("Decimal is not supported in group by keys format"),
+ Column::Decimal(_) => {
+ with_decimal_mapped_type!(|DECIMAL_TYPE| match column {
+ Column::Decimal(DecimalColumn::DECIMAL_TYPE(v, _)) =>
+ vec.extend_from_slice(v[row].to_le_bytes().as_ref()),
+ _ => unreachable!(),
+ })
+ }
Column::Timestamp(v) => vec.extend_from_slice(v[row].to_le_bytes().as_ref()),
Column::Date(v) => vec.extend_from_slice(v[row].to_le_bytes().as_ref()),
Column::Array(array) | Column::Map(array) => {
diff --git a/src/query/expression/src/property.rs b/src/query/expression/src/property.rs
index 1d9587446bcd8..bdc47e5395021 100644
--- a/src/query/expression/src/property.rs
+++ b/src/query/expression/src/property.rs
@@ -34,6 +34,7 @@ use crate::types::NumberType;
use crate::types::StringType;
use crate::types::TimestampType;
use crate::types::ValueType;
+use crate::with_decimal_type;
use crate::with_number_type;
use crate::Scalar;
@@ -193,6 +194,19 @@ impl Domain {
_ => unreachable!("unable to merge {this:?} with {other:?}"),
})
}
+ (Domain::Decimal(this), Domain::Decimal(other)) => {
+ with_decimal_type!(|TYPE| match (this, other) {
+ (DecimalDomain::TYPE(x, size), DecimalDomain::TYPE(y, _)) =>
+ Domain::Decimal(DecimalDomain::TYPE(
+ SimpleDomain {
+ min: x.min.min(y.min),
+ max: x.max.max(y.max),
+ },
+ *size
+ ),),
+ _ => unreachable!("unable to merge {this:?} with {other:?}"),
+ })
+ }
(Domain::Boolean(this), Domain::Boolean(other)) => Domain::Boolean(BooleanDomain {
has_false: this.has_false || other.has_false,
has_true: this.has_true || other.has_true,
diff --git a/src/query/expression/src/type_check.rs b/src/query/expression/src/type_check.rs
index deff57be834e1..0b0582740da0f 100755
--- a/src/query/expression/src/type_check.rs
+++ b/src/query/expression/src/type_check.rs
@@ -25,9 +25,11 @@ use crate::expression::Literal;
use crate::expression::RawExpr;
use crate::function::FunctionRegistry;
use crate::function::FunctionSignature;
+use crate::types::decimal::DecimalSize;
use crate::types::number::NumberDataType;
use crate::types::number::NumberScalar;
use crate::types::DataType;
+use crate::types::DecimalDataType;
use crate::AutoCastRules;
use crate::ColumnIndex;
use crate::Scalar;
@@ -476,7 +478,8 @@ pub fn can_auto_cast_to(
.zip(dest_tys)
.all(|(src_ty, dest_ty)| can_auto_cast_to(src_ty, dest_ty, auto_cast_rules))
}
- (DataType::Number(_) | DataType::Decimal(_), DataType::Decimal(_)) => true,
+ (DataType::Number(_), DataType::Decimal(_)) => true,
+ (DataType::Decimal(x), DataType::Decimal(y)) => x.precision() <= y.precision(),
_ => false,
}
}
@@ -515,11 +518,24 @@ pub fn common_super_type(
.collect::