Merge pull request #28569 from taosdata/merge/mainto3.0
merge: from main to 3.0
This commit is contained in:
commit
d51d3dd414
|
@ -348,7 +348,7 @@ TDengine 提供了丰富的应用程序开发接口,其中包括 C/C++、Java
|
|||
|
||||
# 成为社区贡献者
|
||||
|
||||
点击 [这里](https://www.taosdata.com/cn/contributor/),了解如何成为 TDengine 的贡献者。
|
||||
点击 [这里](https://www.taosdata.com/contributor),了解如何成为 TDengine 的贡献者。
|
||||
|
||||
# 加入技术交流群
|
||||
|
||||
|
|
|
@ -75,9 +75,9 @@ taos>
|
|||
|
||||
## TDegnine Graphic User Interface
|
||||
|
||||
From TDengine 3.3.0.0, there is a new componenet called `taos-explorer` added in the TDengine docker image. You can use it to manage the databases, super tables, child tables, and data in your TDengine system. There are also some features only available in TDengine Enterprise Edition, please contact TDengine sales team in case you need these features.
|
||||
From TDengine 3.3.0.0, there is a new component called `taos-explorer` added in the TDengine docker image. You can use it to manage the databases, super tables, child tables, and data in your TDengine system. There are also some features only available in TDengine Enterprise Edition, please contact TDengine sales team in case you need these features.
|
||||
|
||||
To use taos-explorer in the container, you need to access the host port mapped from container port 6060. Assuming the host name is abc.com, and the port used on host is 6060, you need to access `http://abc.com:6060`. taos-explorer uses port 6060 by default in the container. When you use it the first time, you need to register with your enterprise email, then can logon using your user name and password in the TDengine database management system.
|
||||
To use taos-explorer in the container, you need to access the host port mapped from container port 6060. Assuming the host name is abc.com, and the port used on host is 6060, you need to access `http://abc.com:6060`. taos-explorer uses port 6060 by default in the container. The default username and password to log in to the TDengine Database Management System is "root/taosdata".
|
||||
|
||||
## Test data insert performance
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ sidebar_label: 文档首页
|
|||
slug: /
|
||||
---
|
||||
|
||||
TDengine 是一款[开源](https://www.taosdata.com/tdengine/open_source_time-series_database)、[高性能](https://www.taosdata.com/fast)、[云原生](https://www.taosdata.com/tdengine/cloud_native_time-series_database)的<a href="https://www.taosdata.com/" data-internallinksmanager029f6b8e52c="2" title="时序数据库" target="_blank" rel="noopener">时序数据库</a>(<a href="https://www.taosdata.com/time-series-database" data-internallinksmanager029f6b8e52c="9" title="Time Series DataBase" target="_blank" rel="noopener">Time Series Database</a>, <a href="https://www.taosdata.com/tsdb" data-internallinksmanager029f6b8e52c="8" title="TSDB" target="_blank" rel="noopener">TSDB</a>), 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一款极简的时序数据处理平台。本文档是 TDengine 的用户手册,主要是介绍 TDengine 的基本概念、安装、使用、功能、开发接口、运营维护、TDengine 内核设计等等,它主要是面向架构师、开发工程师与系统管理员的。如果你对时序数据的基本概念、价值以及其所能带来的业务价值尚不了解,请参考[时序数据基础](./concept)
|
||||
TDengine 是一款[开源](https://www.taosdata.com/tdengine/open_source_time-series_database)、[高性能](https://www.taosdata.com/fast)、[云原生](https://www.taosdata.com/tdengine/cloud_native_time-series_database)的<a href="https://www.taosdata.com/" data-internallinksmanager029f6b8e52c="2" title="时序数据库" target="_blank" rel="noopener">时序数据库</a>(<a href="https://www.taosdata.com/time-series-database" data-internallinksmanager029f6b8e52c="9" title="Time Series DataBase" target="_blank" rel="noopener">Time Series Database</a>, <a href="https://www.taosdata.com/tsdb" data-internallinksmanager029f6b8e52c="8" title="TSDB" target="_blank" rel="noopener">TSDB</a>), 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一款极简的时序数据处理平台。本文档是 TDengine 的用户手册,主要是介绍 TDengine 的基本概念、安装、使用、功能、开发接口、运营维护、TDengine 内核设计等等,它主要是面向架构师、开发工程师与系统管理员的。如果你对时序数据的基本概念、价值以及其所能带来的业务价值尚不了解,请参考[时序数据基础](./concept)。
|
||||
|
||||
TDengine 充分利用了时序数据的特点,提出了“一个数据采集点一张表”与“超级表”的概念,设计了创新的存储引擎,让数据的写入、查询和存储效率都得到极大的提升。为正确理解并使用 TDengine,无论如何,请您仔细阅读[数据模型](./basic/model)一章。
|
||||
TDengine 充分利用了时序数据的特点,提出了“一个数据采集点一张表”与“超级表”的概念,设计了创新的存储引擎,让数据的写入、查询和存储效率都得到极大的提升。为正确理解并使用 TDengine,无论你在工作中是什么角色,请您仔细阅读[数据模型](./basic/model)一章。
|
||||
|
||||
如果你是开发工程师,请一定仔细阅读[开发指南](./develop)一章,该部分对数据库连接、建模、插入数据、查询、流式计算、缓存、数据订阅、用户自定义函数等功能都做了详细介绍,并配有各种编程语言的示例代码。大部分情况下,你只要复制粘贴示例代码,针对自己的应用稍作改动,就能跑起来。对 REST API、各种编程语言的连接器(Connector)想做更多详细了解的话,请看[连接器](./reference/connector)一章。
|
||||
|
||||
|
@ -16,6 +16,8 @@ TDengine 采用 SQL 作为查询语言,大大降低学习成本、降低迁移
|
|||
|
||||
如果你是系统管理员,关心安装、升级、容错灾备、关心数据导入、导出、配置参数,如何监测 TDengine 是否健康运行,如何提升系统运行的性能,请仔细参考[运维指南](./operation)一章。
|
||||
|
||||
如果你对数据库内核设计感兴趣,或是开源爱好者,建议仔细阅读[技术内幕](./tdinterna)一章。该章从分布式架构到存储引擎、查询引擎、数据订阅,再到流计算引擎都做了详细阐述。建议对照文档,查看TDengine在GitHub的源代码,对TDengine的设计和编码做深入了解,更欢迎加入开源社区,贡献代码。
|
||||
|
||||
最后,作为一个开源软件,欢迎大家的参与。如果发现文档有任何错误、描述不清晰的地方,请在每个页面的最下方,点击“编辑本文档”直接进行修改。
|
||||
|
||||
Together, we make a difference!
|
||||
|
|
|
@ -14,7 +14,9 @@ TDengine 完整的软件包包括服务端(taosd)、应用驱动(taosc)
|
|||
|
||||
为方便使用,标准的服务端安装包包含了 taosd、taosAdapter、taosc、taos、taosdump、taosBenchmark、TDinsight 安装脚本和示例代码;如果您只需要用到服务端程序和客户端连接的 C/C++ 语言支持,也可以仅下载 Lite 版本的安装包。
|
||||
|
||||
在 Linux 系统上,TDengine 社区版提供 Deb 和 RPM 格式安装包,用户可以根据自己的运行环境选择合适的安装包。其中 Deb 支持 Debian/Ubuntu 及其衍生系统,RPM 支持 CentOS/RHEL/SUSE 及其衍生系统。同时我们也为企业用户提供 tar.gz 格式安装包,也支持通过 `apt-get` 工具从线上进行安装。需要注意的是,RPM 和 Deb 包不含 `taosdump` 和 TDinsight 安装脚本,这些工具需要通过安装 taosTools 包获得。TDengine 也提供 Windows x64 平台和 macOS x64/m1 平台的安装包。
|
||||
在 Linux 系统上,TDengine 社区版提供 Deb 和 RPM 格式安装包,其中 Deb 支持 Debian/Ubuntu 及其衍生系统,RPM 支持 CentOS/RHEL/SUSE 及其衍生系统,用户可以根据自己的运行环境自行选择。同时我们也提供了 tar.gz 格式安装包,以及 `apt-get` 工具从线上进行安装。
|
||||
|
||||
此外,TDengine 也提供 macOS x64/m1 平台的 pkg 安装包。
|
||||
|
||||
## 运行环境要求
|
||||
在linux系统中,运行环境最低要求如下:
|
||||
|
|
|
@ -54,7 +54,7 @@ TDengine 利用这些日志文件实现故障前的状态恢复。在写入 WAL
|
|||
|
||||
数据库参数 wal_level 和 wal_fsync_period 共同决定了 WAL 的保存行为。。
|
||||
- wal_level:此参数控制 WAL 的保存级别。级别 1 表示仅将数据写入 WAL,但不立即执行 fsync 函数;级别 2 则表示在写入 WAL 的同时执行 fsync 函数。默认情况下,wal_level 设为 1。虽然执行 fsync 函数可以提高数据的持久性,但相应地也会降低写入性能。
|
||||
- wal_fsync_period:当 wal_level 设置为 2 时,这个参数控制执行 fsync 的频率。设置为 0 表示每次写入后立即执行 fsync,这可以确保数据的安全性,但可能会牺牲一些性能。当设置为大于 0 的数值时,表示 fsync 周期,默认为 3000,范围是[1, 180000],单位毫秒。
|
||||
- wal_fsync_period:当 wal_level 设置为 1 时,这个参数控制执行 fsync 的频率。设置为 0 表示每次写入后立即执行 fsync,这可以确保数据的安全性,但可能会牺牲一些性能。当设置为大于 0 的数值时,表示 fsync 周期,默认为 3000,范围是[1, 180000],单位毫秒。
|
||||
|
||||
```sql
|
||||
CREATE DATABASE POWER WAL_LEVEL 1 WAL_FSYNC_PERIOD 3000;
|
||||
|
@ -119,4 +119,4 @@ taos> select last_row(ts,current) from meters;
|
|||
Query OK, 1 row(s) in set (0.046682s)
|
||||
```
|
||||
|
||||
可以看到查询的时延从 353/344ms 缩短到了 44ms,提升约 8 倍。
|
||||
可以看到查询的时延从 353/344ms 缩短到了 44ms,提升约 8 倍。
|
||||
|
|
|
@ -368,6 +368,18 @@ spec:
|
|||
labels:
|
||||
app: "tdengine"
|
||||
spec:
|
||||
affinity:
|
||||
podAntiAffinity:
|
||||
preferredDuringSchedulingIgnoredDuringExecution:
|
||||
- weight: 100
|
||||
podAffinityTerm:
|
||||
labelSelector:
|
||||
matchExpressions:
|
||||
- key: app
|
||||
operator: In
|
||||
values:
|
||||
- tdengine
|
||||
topologyKey: kubernetes.io/hostname
|
||||
containers:
|
||||
- name: "tdengine"
|
||||
image: "tdengine/tdengine:3.2.3.0"
|
||||
|
@ -837,4 +849,4 @@ Helm 管理下,清理操作也变得简单:
|
|||
helm uninstall tdengine
|
||||
```
|
||||
|
||||
但 Helm 也不会自动移除 PVC,需要手动获取 PVC 然后删除掉。
|
||||
但 Helm 也不会自动移除 PVC,需要手动获取 PVC 然后删除掉。
|
||||
|
|
|
@ -33,7 +33,7 @@ taosd 命令行参数如下
|
|||
| secondEp | taosd 启动时,如果 firstEp 连接不上,尝试连接集群中第二个 dnode 的 endpoint,缺省值:无 |
|
||||
| fqdn | 启动 taosd 后所监听的服务地址,缺省值:所在服务器上配置的第一个 hostname |
|
||||
| serverPort | 启动 taosd 后所监听的端口,缺省值:6030 |
|
||||
| numOfRpcSessions | 允许一个客户端能创建的最大连接数,取值范围 100-100000,缺省值:30000 |
|
||||
| numOfRpcSessions | 允许一个 dnode 能发起的最大连接数,取值范围 100-100000,缺省值:30000 |
|
||||
| timeToGetAvailableConn | 获得可用连接的最长等待时间,取值范围 10-50000000,单位为毫秒,缺省值:500000 |
|
||||
|
||||
### 监控相关
|
||||
|
@ -458,3 +458,4 @@ TDengine 的日志文件主要包括普通日志和慢日志两种类型。
|
|||
3. 多个客户端的日志存储在相应日志路径下的同一个 taosSlowLog.yyyy.mm.dd 文件里。
|
||||
4. 慢日志文件不自动删除,不压缩。
|
||||
5. 使用和普通日志文件相同的三个参数 logDir, minimalLogDirGB, asyncLog。另外两个参数 numOfLogLines,logKeepDays 不适用于慢日志。
|
||||
|
||||
|
|
|
@ -212,11 +212,11 @@ TDengine 对于修改数据提供两种处理方式,由 IGNORE UPDATE 选项
|
|||
```sql
|
||||
[field1_name,...]
|
||||
```
|
||||
用来指定stb_name的列与subquery输出结果的对应关系。如果stb_name的列与subquery输出结果的位置、数量全部匹配,则不需要显示指定对应关系。如果stb_name的列与subquery输出结果的数据类型不匹配,会把subquery输出结果的类型转换成对应的stb_name的列的类型。
|
||||
在本页文档顶部的 [field1_name,...] 是用来指定 stb_name 的列与 subquery 输出结果的对应关系的。如果 stb_name 的列与 subquery 输出结果的位置、数量全部匹配,则不需要显示指定对应关系。如果 stb_name 的列与 subquery 输出结果的数据类型不匹配,会把 subquery 输出结果的类型转换成对应的 stb_name 的列的类型。
|
||||
|
||||
对于已经存在的超级表,检查列的schema信息
|
||||
1. 检查列的schema信息是否匹配,对于不匹配的,则自动进行类型转换,当前只有数据长度大于4096byte时才报错,其余场景都能进行类型转换。
|
||||
2. 检查列的个数是否相同,如果不同,需要显示的指定超级表与subquery的列的对应关系,否则报错;如果相同,可以指定对应关系,也可以不指定,不指定则按位置顺序对应。
|
||||
1. 检查列的 schema 信息是否匹配,对于不匹配的,则自动进行类型转换,当前只有数据长度大于 4096byte 时才报错,其余场景都能进行类型转换。
|
||||
2. 检查列的个数是否相同,如果不同,需要显示的指定超级表与 subquery 的列的对应关系,否则报错;如果相同,可以指定对应关系,也可以不指定,不指定则按位置顺序对应。
|
||||
|
||||
## 自定义TAG
|
||||
|
||||
|
|
|
@ -6,15 +6,28 @@ description: "TDengine 服务端、客户端和连接器支持的平台列表"
|
|||
|
||||
## TDengine 服务端支持的平台列表
|
||||
|
||||
| | **Windows server 2016/2019** | **Windows 10/11** | **CentOS 7.9/8** | **Ubuntu 18 以上** | **统信 UOS** | **银河/中标麒麟** | **凝思 V60/V80** | **macOS** |
|
||||
| ------------ | ---------------------------- | ----------------- | ---------------- | ------------------ | ------------ | ----------------- | ---------------- | --------- |
|
||||
| X64 | ●/E | ●/E | ● | ● | ●/E | ●/E | ●/E | ● |
|
||||
| 树莓派 ARM64 | | | ● | | | | | |
|
||||
| 华为云 ARM64 | | | | ● | | | | |
|
||||
| M1 | | | | | | | | ● |
|
||||
| | **版本** | **X64 64bit** | **ARM64** |
|
||||
| ----------------------|----------------| ------------- | --------- |
|
||||
| **CentOS** | **7.9 以上** | ● | ● |
|
||||
| **Ubuntu** | **18 以上** | ● | ● |
|
||||
| **RedHat** | **RHEL 7 以上** | ● | ● |
|
||||
| **Debian** | **6.0 以上** | ● | ● |
|
||||
| **FreeBSD** | **12 以上** | ● | ● |
|
||||
| **OpenSUSE** | **全部版本** | ● | ● |
|
||||
| **SUSE Linux** | **11 以上** | ● | ● |
|
||||
| **Fedora** | **21 以上** | ● | ● |
|
||||
| **Windows Server** | **2016 以上** | ●/E | |
|
||||
| **Windows** | **10/11** | ●/E | |
|
||||
| **银河麒麟** | **V10 以上** | ●/E | ●/E |
|
||||
| **中标麒麟** | **V7.0 以上** | ●/E | ●/E |
|
||||
| **统信 UOS** | **V20 以上** | ●/E | |
|
||||
| **凝思磐石** | **V8.0 以上** | ●/E | |
|
||||
| **华为欧拉 openEuler** | **V20.03 以上** | ●/E | |
|
||||
| **龙蜥 Anolis OS** | **V8.6 以上** | ●/E | |
|
||||
| **macOS** | **11.0 以上** | | ● |
|
||||
|
||||
注:1) ● 表示经过官方测试验证, ○ 表示非官方测试验证,E 表示仅企业版支持。
|
||||
2) 社区版仅支持主流操作系统的较新版本,包括 Ubuntu 18+/CentOS 7+/RedHat/Debian/CoreOS/FreeBSD/OpenSUSE/SUSE Linux/Fedora/macOS 等。如果有其他操作系统及版本的需求,请联系企业版支持。
|
||||
2) 社区版仅支持主流操作系统的较新版本,包括 Ubuntu 18+/CentOS 7+/CentOS Stream/RedHat/Debian/CoreOS/FreeBSD/OpenSUSE/SUSE Linux/Fedora/macOS 等。如果有其他操作系统及版本的需求,请联系企业版支持。
|
||||
|
||||
## TDengine 客户端和连接器支持的平台列表
|
||||
|
||||
|
@ -22,16 +35,16 @@ description: "TDengine 服务端、客户端和连接器支持的平台列表"
|
|||
|
||||
对照矩阵如下:
|
||||
|
||||
| **CPU** | **X64 64bit** | **X64 64bit** | **ARM64** | **X64 64bit** | **ARM64** |
|
||||
| ----------- | ------------- | ------------- | --------- | ------------- | --------- |
|
||||
| **OS** | **Linux** | **Win64** | **Linux** | **macOS** | **macOS** |
|
||||
| **C/C++** | ● | ● | ● | ● | ● |
|
||||
| **JDBC** | ● | ● | ● | ● | ● |
|
||||
| **Python** | ● | ● | ● | ● | ● |
|
||||
| **Go** | ● | ● | ● | ● | ● |
|
||||
| **NodeJs** | ● | ● | ● | ● | ● |
|
||||
| **C#** | ● | ● | ○ | ○ | ○ |
|
||||
| **Rust** | ● | ● | ○ | ● | ● |
|
||||
| **RESTful** | ● | ● | ● | ● | ● |
|
||||
| **CPU** | **X64 64bit** | **X64 64bit** | **X64 64bit** | **ARM64** | **ARM64** |
|
||||
| ----------- | ------------- | ------------- | ------------- | --------- | --------- |
|
||||
| **OS** | **Linux** | **Win64** | **macOS** | **Linux** | **macOS** |
|
||||
| **C/C++** | ● | ● | ● | ● | ● |
|
||||
| **JDBC** | ● | ● | ● | ● | ● |
|
||||
| **Python** | ● | ● | ● | ● | ● |
|
||||
| **Go** | ● | ● | ● | ● | ● |
|
||||
| **NodeJs** | ● | ● | ● | ● | ● |
|
||||
| **C#** | ● | ● | ○ | ● | ○ |
|
||||
| **Rust** | ● | ● | ● | ○ | ● |
|
||||
| **RESTful** | ● | ● | ● | ● | ● |
|
||||
|
||||
注:● 表示官方测试验证通过,○ 表示非官方测试验证通过,-- 表示未经验证。
|
||||
|
|
|
@ -178,7 +178,7 @@ TDengine 集群可以容纳单个、多个甚至几千个数据节点。应用
|
|||
|
||||
TDengine 存储的数据包括采集的时序数据以及库、表相关的元数据、标签数据等,这些数据具体分为三部分:
|
||||
|
||||
- 时序数据:TDengine 的核心存储对象,存放于 vnode 里,由 data、head 和 last 三个文件组成,数据量大,查询量取决于应用场景。允许乱序写入,但暂时不支持删除操作,并且仅在 update 参数设置为 1 时允许更新操作。通过采用一个采集点一张表的模型,一个时间段的数据是连续存储,对单张表的写入是简单的追加操作,一次读,可以读到多条记录,这样保证对单个采集点的插入和查询操作,性能达到最优。
|
||||
- 时序数据:时序数据是 TDengine 的核心存储对象,它们被存储在 vnode 中。时序数据由 data、head、sma 和 stt 4 类文件组成,这些文件共同构成了时序数据的完整存储结构。由于时序数据的特点是数据量大且查询需求取决于具体应用场景,因此 TDengine 采用了“一个数据采集点一张表”的模型来优化存储和查询性能。在这种模型下,一个时间段内的数据是连续存储的,对单张表的写入是简单的追加操作,一次读取可以获取多条记录。这种设计确保了单个数据采集点的写入和查询操作都能达到最优性能。
|
||||
- 数据表元数据:包含标签信息和 Table Schema 信息,存放于 vnode 里的 meta 文件,支持增删改查四个标准操作。数据量很大,有 N 张表,就有 N 条记录,因此采用 LRU 存储,支持标签数据的索引。TDengine 支持多核多线程并发查询。只要计算内存足够,元数据全内存存储,千万级别规模的标签数据过滤结果能毫秒级返回。在内存资源不足的情况下,仍然可以支持数千万张表的快速查询。
|
||||
- 数据库元数据:存放于 mnode 里,包含系统节点、用户、DB、STable Schema 等信息,支持增删改查四个标准操作。这部分数据的量不大,可以全内存保存,而且由于客户端有缓存,查询量也不大。因此目前的设计虽是集中式存储管理,但不会构成性能瓶颈。
|
||||
|
||||
|
@ -321,4 +321,4 @@ TDengine 采用了一种数据驱动的策略来实现缓存数据的持久化
|
|||
|
||||
此外,TDengine 还提供了数据分级存储的功能,允许用户将不同时间段的数据存储在不同存储设备的目录中,以此实现将“热”数据和“冷”数据分开存储。这样做可以充分利用各种存储资源,同时节约成本。例如,对于最新采集且需要频繁访问的数据,由于其读取性能要求较高,用户可以配置将这些数据存储在高性能的固态硬盘上。而对于超过一定期限、查询需求较低的数据,则可以将其存储在成本相对较低的机械硬盘上。
|
||||
|
||||
为了进一步降低存储成本,TDengine 还支持将时序数据存储在对象存储系统中。通过其创新性的设计,在大多数情况下,从对象存储系统中查询时序数据的性能接近本地硬盘的一半,而在某些场景下,性能甚至可以与本地硬盘相媲美。同时,TDengine 还允许用户对存储在对象存储中的时序数据执行删除和更新操作。
|
||||
为了进一步降低存储成本,TDengine 还支持将时序数据存储在对象存储系统中。通过其创新性的设计,在大多数情况下,从对象存储系统中查询时序数据的性能接近本地硬盘的一半,而在某些场景下,性能甚至可以与本地硬盘相媲美。同时,TDengine 还允许用户对存储在对象存储中的时序数据执行删除和更新操作。
|
||||
|
|
|
@ -1607,26 +1607,6 @@ static EDealRes translateColumnUseAlias(STranslateContext* pCxt, SColumnNode** p
|
|||
}
|
||||
}
|
||||
if (*pFound) {
|
||||
if (QUERY_NODE_FUNCTION == nodeType(pFoundNode) &&
|
||||
(SQL_CLAUSE_GROUP_BY == pCxt->currClause || SQL_CLAUSE_PARTITION_BY == pCxt->currClause)) {
|
||||
pCxt->errCode = getFuncInfo(pCxt, (SFunctionNode*)pFoundNode);
|
||||
if (TSDB_CODE_SUCCESS == pCxt->errCode) {
|
||||
if (fmIsVectorFunc(((SFunctionNode*)pFoundNode)->funcId)) {
|
||||
pCxt->errCode = generateSyntaxErrMsg(&pCxt->msgBuf, TSDB_CODE_PAR_ILLEGAL_USE_AGG_FUNCTION, (*pCol)->colName);
|
||||
return DEAL_RES_ERROR;
|
||||
} else if (fmIsPseudoColumnFunc(((SFunctionNode*)pFoundNode)->funcId)) {
|
||||
if ('\0' != (*pCol)->tableAlias[0]) {
|
||||
return translateColumnWithPrefix(pCxt, pCol);
|
||||
} else {
|
||||
return translateColumnWithoutPrefix(pCxt, pCol);
|
||||
}
|
||||
} else {
|
||||
/* Do nothing and replace old node with found node. */
|
||||
}
|
||||
} else {
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
}
|
||||
SNode* pNew = NULL;
|
||||
int32_t code = nodesCloneNode(pFoundNode, &pNew);
|
||||
if (NULL == pNew) {
|
||||
|
@ -1635,14 +1615,6 @@ static EDealRes translateColumnUseAlias(STranslateContext* pCxt, SColumnNode** p
|
|||
}
|
||||
nodesDestroyNode(*(SNode**)pCol);
|
||||
*(SNode**)pCol = (SNode*)pNew;
|
||||
if (QUERY_NODE_COLUMN == nodeType(pFoundNode)) {
|
||||
pCxt->errCode = TSDB_CODE_SUCCESS;
|
||||
if ('\0' != (*pCol)->tableAlias[0]) {
|
||||
return translateColumnWithPrefix(pCxt, pCol);
|
||||
} else {
|
||||
return translateColumnWithoutPrefix(pCxt, pCol);
|
||||
}
|
||||
}
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
@ -1881,6 +1853,39 @@ static bool clauseSupportAlias(ESqlClause clause) {
|
|||
return SQL_CLAUSE_GROUP_BY == clause || SQL_CLAUSE_PARTITION_BY == clause || SQL_CLAUSE_ORDER_BY == clause;
|
||||
}
|
||||
|
||||
static EDealRes translateColumnInGroupByClause(STranslateContext* pCxt, SColumnNode** pCol, bool *translateAsAlias) {
|
||||
*translateAsAlias = false;
|
||||
// count(*)/first(*)/last(*) and so on
|
||||
if (0 == strcmp((*pCol)->colName, "*")) {
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
if (pCxt->pParseCxt->biMode) {
|
||||
SNode** ppNode = (SNode**)pCol;
|
||||
bool ret;
|
||||
pCxt->errCode = biRewriteToTbnameFunc(pCxt, ppNode, &ret);
|
||||
if (TSDB_CODE_SUCCESS != pCxt->errCode) return DEAL_RES_ERROR;
|
||||
if (ret) {
|
||||
return translateFunction(pCxt, (SFunctionNode**)ppNode);
|
||||
}
|
||||
}
|
||||
|
||||
EDealRes res = DEAL_RES_CONTINUE;
|
||||
if ('\0' != (*pCol)->tableAlias[0]) {
|
||||
res = translateColumnWithPrefix(pCxt, pCol);
|
||||
} else {
|
||||
bool found = false;
|
||||
res = translateColumnWithoutPrefix(pCxt, pCol);
|
||||
if (!(*pCol)->node.asParam &&
|
||||
res != DEAL_RES_CONTINUE &&
|
||||
res != DEAL_RES_END && pCxt->errCode != TSDB_CODE_PAR_AMBIGUOUS_COLUMN) {
|
||||
res = translateColumnUseAlias(pCxt, pCol, &found);
|
||||
*translateAsAlias = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static EDealRes translateColumn(STranslateContext* pCxt, SColumnNode** pCol) {
|
||||
if (NULL == pCxt->pCurrStmt ||
|
||||
(isSelectStmt(pCxt->pCurrStmt) && NULL == ((SSelectStmt*)pCxt->pCurrStmt)->pFromTable)) {
|
||||
|
@ -5464,13 +5469,14 @@ typedef struct SReplaceGroupByAliasCxt {
|
|||
SNodeList* pProjectionList;
|
||||
} SReplaceGroupByAliasCxt;
|
||||
|
||||
static EDealRes replaceGroupByAliasImpl(SNode** pNode, void* pContext) {
|
||||
static EDealRes translateGroupPartitionByImpl(SNode** pNode, void* pContext) {
|
||||
SReplaceGroupByAliasCxt* pCxt = pContext;
|
||||
SNodeList* pProjectionList = pCxt->pProjectionList;
|
||||
SNode* pProject = NULL;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
STranslateContext* pTransCxt = pCxt->pTranslateCxt;
|
||||
if (QUERY_NODE_VALUE == nodeType(*pNode)) {
|
||||
STranslateContext* pTransCxt = pCxt->pTranslateCxt;
|
||||
SValueNode* pVal = (SValueNode*)*pNode;
|
||||
SValueNode* pVal = (SValueNode*) *pNode;
|
||||
if (DEAL_RES_ERROR == translateValue(pTransCxt, pVal)) {
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
@ -5479,42 +5485,60 @@ static EDealRes replaceGroupByAliasImpl(SNode** pNode, void* pContext) {
|
|||
}
|
||||
int32_t pos = getPositionValue(pVal);
|
||||
if (0 < pos && pos <= LIST_LENGTH(pProjectionList)) {
|
||||
SNode* pNew = NULL;
|
||||
int32_t code = nodesCloneNode(nodesListGetNode(pProjectionList, pos - 1), (SNode**)&pNew);
|
||||
SNode* pNew = NULL;
|
||||
code = nodesCloneNode(nodesListGetNode(pProjectionList, pos - 1), (SNode**)&pNew);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
pCxt->pTranslateCxt->errCode = code;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
nodesDestroyNode(*pNode);
|
||||
*pNode = pNew;
|
||||
return DEAL_RES_CONTINUE;
|
||||
} else {
|
||||
}
|
||||
code = translateExpr(pTransCxt, pNode);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
pTransCxt->errCode = code;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
} else if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
bool asAlias = false;
|
||||
EDealRes res = translateColumnInGroupByClause(pTransCxt, (SColumnNode**)pNode, &asAlias);
|
||||
if (DEAL_RES_ERROR == res) {
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
pTransCxt->errCode = TSDB_CODE_SUCCESS;
|
||||
if (nodeType(*pNode) == QUERY_NODE_COLUMN && !asAlias) {
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
} else if (QUERY_NODE_COLUMN == nodeType(*pNode)) {
|
||||
STranslateContext* pTransCxt = pCxt->pTranslateCxt;
|
||||
return translateColumn(pTransCxt, (SColumnNode**)pNode);
|
||||
code = translateExpr(pTransCxt, pNode);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
pTransCxt->errCode = code;
|
||||
return DEAL_RES_ERROR;
|
||||
}
|
||||
return DEAL_RES_CONTINUE;
|
||||
}
|
||||
|
||||
return DEAL_RES_CONTINUE;
|
||||
return doTranslateExpr(pNode, pTransCxt);
|
||||
}
|
||||
|
||||
static int32_t replaceGroupByAlias(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
static int32_t translateGroupByList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
if (NULL == pSelect->pGroupByList) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
SReplaceGroupByAliasCxt cxt = {.pTranslateCxt = pCxt, .pProjectionList = pSelect->pProjectionList};
|
||||
nodesRewriteExprsPostOrder(pSelect->pGroupByList, replaceGroupByAliasImpl, &cxt);
|
||||
SReplaceGroupByAliasCxt cxt = {
|
||||
.pTranslateCxt = pCxt, .pProjectionList = pSelect->pProjectionList};
|
||||
nodesRewriteExprsPostOrder(pSelect->pGroupByList, translateGroupPartitionByImpl, &cxt);
|
||||
|
||||
return pCxt->errCode;
|
||||
}
|
||||
|
||||
static int32_t replacePartitionByAlias(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
static int32_t translatePartitionByList(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
||||
if (NULL == pSelect->pPartitionByList) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
SReplaceGroupByAliasCxt cxt = {.pTranslateCxt = pCxt, .pProjectionList = pSelect->pProjectionList};
|
||||
nodesRewriteExprsPostOrder(pSelect->pPartitionByList, replaceGroupByAliasImpl, &cxt);
|
||||
|
||||
SReplaceGroupByAliasCxt cxt = {
|
||||
.pTranslateCxt = pCxt, .pProjectionList = pSelect->pProjectionList};
|
||||
nodesRewriteExprsPostOrder(pSelect->pPartitionByList, translateGroupPartitionByImpl, &cxt);
|
||||
|
||||
return pCxt->errCode;
|
||||
}
|
||||
|
@ -5578,11 +5602,8 @@ static int32_t translateGroupBy(STranslateContext* pCxt, SSelectStmt* pSelect) {
|
|||
NODES_DESTORY_LIST(pSelect->pGroupByList);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
code = replaceGroupByAlias(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
pSelect->timeLineResMode = TIME_LINE_NONE;
|
||||
code = translateExprList(pCxt, pSelect->pGroupByList);
|
||||
code = translateGroupByList(pCxt, pSelect);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
@ -6277,10 +6298,7 @@ static int32_t translatePartitionBy(STranslateContext* pCxt, SSelectStmt* pSelec
|
|||
(QUERY_NODE_FUNCTION == nodeType(pPar) && FUNCTION_TYPE_TBNAME == ((SFunctionNode*)pPar)->funcType))) {
|
||||
pSelect->timeLineResMode = TIME_LINE_MULTI;
|
||||
}
|
||||
code = replacePartitionByAlias(pCxt, pSelect);
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateExprList(pCxt, pSelect->pPartitionByList);
|
||||
}
|
||||
code = translatePartitionByList(pCxt, pSelect);
|
||||
}
|
||||
if (TSDB_CODE_SUCCESS == code) {
|
||||
code = translateExprList(pCxt, pSelect->pTags);
|
||||
|
|
|
@ -420,7 +420,23 @@ class TDTestCase:
|
|||
tdSql.error(f"select t2, count(*) from {self.dbname}.{self.stable} group by t2 where t2 = 1")
|
||||
tdSql.error(f"select t2, count(*) from {self.dbname}.{self.stable} group by t2 interval(1d)")
|
||||
|
||||
|
||||
def test_TS5567(self):
|
||||
tdSql.query(f"select const_col from (select 1 as const_col from {self.dbname}.{self.stable}) t group by const_col")
|
||||
tdSql.checkRows(50)
|
||||
tdSql.query(f"select const_col from (select 1 as const_col from {self.dbname}.{self.stable}) t partition by const_col")
|
||||
tdSql.checkRows(50)
|
||||
tdSql.query(f"select const_col from (select 1 as const_col, count(c1) from {self.dbname}.{self.stable} t group by c1) group by const_col")
|
||||
tdSql.checkRows(10)
|
||||
tdSql.query(f"select const_col from (select 1 as const_col, count(c1) from {self.dbname}.{self.stable} t group by c1) partition by const_col")
|
||||
tdSql.checkRows(10)
|
||||
tdSql.query(f"select const_col as c_c from (select 1 as const_col from {self.dbname}.{self.stable}) t group by c_c")
|
||||
tdSql.checkRows(50)
|
||||
tdSql.query(f"select const_col as c_c from (select 1 as const_col from {self.dbname}.{self.stable}) t partition by c_c")
|
||||
tdSql.checkRows(50)
|
||||
tdSql.query(f"select const_col from (select 1 as const_col, count(c1) from {self.dbname}.{self.stable} t group by c1) group by 1")
|
||||
tdSql.checkRows(10)
|
||||
tdSql.query(f"select const_col from (select 1 as const_col, count(c1) from {self.dbname}.{self.stable} t group by c1) partition by 1")
|
||||
tdSql.checkRows(10)
|
||||
def run(self):
|
||||
tdSql.prepare()
|
||||
self.prepare_db()
|
||||
|
@ -453,6 +469,7 @@ class TDTestCase:
|
|||
self.test_window(nonempty_tb_num)
|
||||
self.test_event_window(nonempty_tb_num)
|
||||
|
||||
self.test_TS5567()
|
||||
|
||||
## test old version before changed
|
||||
# self.test_groupby('group', 0, 0)
|
||||
|
|
Loading…
Reference in New Issue