diff --git a/.gitignore b/.gitignore index 0458aa3415dc61005fe77b38c7c3366b1fcf461c..0eba25231f2a4961dd31f847458850a455788a58 100644 --- a/.gitignore +++ b/.gitignore @@ -86,7 +86,6 @@ tests/script/api/batchprepare tests/script/api/stmt tests/script/api/stmtBatchTest tests/script/api/stmtTest - # Emacs # -*- mode: gitignore; -*- *~ diff --git a/Jenkinsfile b/Jenkinsfile index 9d131d0ca500ef248740b5ce31fd92ce197b32f8..f2e3c1c4f6c3754f33f56575c4f6b89170e36948 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -450,7 +450,7 @@ pipeline { stage('test_b1_s2') { agent{label " slave2 || slave12 "} steps { - timeout(time: 55, unit: 'MINUTES'){ + timeout(time: 105, unit: 'MINUTES'){ pre_test() sh ''' rm -rf /var/lib/taos/* diff --git a/cmake/define.inc b/cmake/define.inc index 6877ee7257cab244c6cc2872e44fa899a798c856..9e39dc9463f63c935ec67dbb712377dc3d0ac96f 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -265,7 +265,7 @@ IF (TD_WINDOWS) ADD_DEFINITIONS(-D_MBCS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE) SET(CMAKE_GENERATOR "NMake Makefiles" CACHE INTERNAL "" FORCE) IF (NOT TD_GODLL) - SET(COMMON_FLAGS "/nologo /WX /wd4018 /wd5999 /Oi /Oy- /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /errorReport:prompt /analyze-") + SET(COMMON_FLAGS "/nologo /WX /wd4018 /wd4999 /Oi /Oy- /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /errorReport:prompt /analyze-") IF (MSVC AND (MSVC_VERSION GREATER_EQUAL 1900)) SET(COMMON_FLAGS "${COMMON_FLAGS} /Wv:18") ENDIF () diff --git a/documentation20/cn/08.connector/docs.md b/documentation20/cn/08.connector/docs.md index 7806de6093b422b40938b701d85c1512b32945ec..ee5d8e9f825e12bd65331736ecb23db62e5fe388 100644 --- a/documentation20/cn/08.connector/docs.md +++ b/documentation20/cn/08.connector/docs.md @@ -55,7 +55,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、 ​ *install_client.sh*:安装脚本,用于应用驱动程序 ​ *taos.tar.gz*:应用驱动安装包 ​ *driver*:TDengine应用驱动driver -​ *connector*: 各种编程语言连接器(go/grafanaplugin/nodejs/python/JDBC) +​ *connector*: 各种编程语言连接器(go/nodejs/python/JDBC) ​ *examples*: 各种编程语言的示例程序(c/C#/go/JDBC/MATLAB/python/R) 运行install_client.sh进行安装。 @@ -541,9 +541,8 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时 Python连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020/11/11/1963.html) -**安装**:参见下面具体步骤 - -**示例程序**:位于install_directory/examples/python +* **安装**:参见下面具体步骤 +* **示例程序**:位于install_directory/examples/python ### 安装 @@ -557,47 +556,36 @@ Python连接器支持的系统有:Linux 64/Windows x64 ### Python连接器安装 -**Linux** - -用户可以在源代码的src/connector/python(或者tar.gz的/connector/python)文件夹下找到connector安装包。用户可以通过pip命令安装: - -​ `pip install src/connector/python/` +Python 连接器可以通过 `pip` 从 PyPI 下载安装。注意 TDengine Python 连接器的包名为 `taospy` 而不是 `taos`(这是一个与 TDengine 无关的另一个程序)。但为保持向后兼容性,仍然使用 `import taos` 导入。 -或 - -​ `pip3 install src/connector/python/` - -**Windows** - -在已安装Windows TDengine 客户端的情况下, 将文件"C:\TDengine\driver\taos.dll" 拷贝到 "C:\Windows\system32" 目录下, 然后进入Windows *cmd* 命令行界面 ```bash -cd C:\TDengine\connector\python -python -m pip install . +pip install taospy ``` -**PyPI** +如果不使用系统默认的 `python` 和 `pip`,则需要指定 `pip` 的版本或路径: -从2.1.1版本开始,用户可以从[PyPI](https://pypi.org/project/taospy/)安装: - -```sh -pip install taospy +```bash +pip2 install taospy +pip3 install taospy ``` -* 如果机器上没有pip命令,用户可将src/connector/python下的taos文件夹拷贝到应用程序的目录使用。 -对于windows 客户端,安装TDengine windows 客户端后,将C:\TDengine\driver\taos.dll拷贝到C:\windows\system32目录下即可。 +Python 命令行依赖 taos 动态库 `libtaos.so` 或 `taos.dll`, 对于 Windows 客户端,安装TDengine windows 客户端后,如果不能正常 `import taos`,可以将 `C:\TDengine\driver\taos.dll` 拷贝到 `C:\windows\system32` 目录后重新尝试。 + +对于无法联网用户,可以将TDengine客户端中的 `connector/python` 路径(Linux 下其安装路径为 `/usr/local/taos/connector/python/`,Windows 下默认安装路径为 `C:\TDengine\connector\python`)添加到 `PYTHONPATH` 环境变量中使用。 ### 示例程序 -示例程序源码位于install_directory/examples/Python,有: -**read_example.py Python示例源程序** +示例程序源码位于 `/examples/python`,有: + +* **read_example.py** Python示例源程序 -用户可以参考read_example.py这个程序来设计用户自己的写入、查询程序。 +用户可以参考`read_example.py`这个程序来设计用户自己的写入、查询程序。 -在安装了对应的应用驱动后,通过import taos引入taos类。主要步骤如下: +在安装了对应的应用驱动后,通过`import taos`引入taos类。主要步骤如下: -- 通过taos.connect获取TDengineConnection对象,这个对象可以一个程序只申请一个,在多线程中共享。 +- 通过taos.connect获取TaosConnection对象,这个对象可以一个程序只申请一个,在多线程中共享。 -- 通过TDengineConnection对象的 .cursor()方法获取一个新的游标对象,这个游标对象必须保证每个线程独享。 +- 通过TaosConnection对象的 `.cursor()` 方法获取一个新的游标对象,这个游标对象必须保证每个线程独享。 - 通过游标对象的execute()方法,执行写入或查询的SQL语句。 @@ -634,127 +622,132 @@ for row in results: print(row) ``` -#### 代码示例 +##### 代码示例 -* 导入TDengine客户端模块 +1. 导入TDengine客户端模块 -```python -import taos -``` -* 获取连接并获取游标对象 + ```python + import taos + ``` -```python -conn = taos.connect(host="127.0.0.1", user="root", password="taosdata", config="/etc/taos") -c1 = conn.cursor() -``` -* *host* 是TDengine 服务端所有IP, *config* 为客户端配置文件所在目录 +2. 获取连接并获取游标对象 -* 写入数据 + ```python + conn = taos.connect(host="127.0.0.1", user="root", password="taosdata", config="/etc/taos") + c1 = conn.cursor() + ``` -```python -import datetime - -# 创建数据库 -c1.execute('create database db') -c1.execute('use db') -# 建表 -c1.execute('create table tb (ts timestamp, temperature int, humidity float)') -# 插入数据 -start_time = datetime.datetime(2019, 11, 1) -affected_rows = c1.execute('insert into tb values (\'%s\', 0, 0.0)' %start_time) -# 批量插入数据 -time_interval = datetime.timedelta(seconds=60) -sqlcmd = ['insert into tb values'] -for irow in range(1,11): - start_time += time_interval - sqlcmd.append('(\'%s\', %d, %f)' %(start_time, irow, irow*1.2)) -affected_rows = c1.execute(' '.join(sqlcmd)) -``` + *host* 是TDengine 服务端所在IP, *config* 为客户端配置文件所在目录。 -* 查询数据 +3. 写入数据 -```python -c1.execute('select * from tb') -# 拉取查询结果 -data = c1.fetchall() -# 返回的结果是一个列表,每一行构成列表的一个元素 -numOfRows = c1.rowcount -numOfCols = len(c1.description) -for irow in range(numOfRows): - print("Row%d: ts=%s, temperature=%d, humidity=%f" %(irow, data[irow][0], data[irow][1],data[irow][2])) - -# 直接使用cursor 循环拉取查询结果 -c1.execute('select * from tb') -for data in c1: - print("ts=%s, temperature=%d, humidity=%f" %(data[0], data[1],data[2])) -``` + ```python + import datetime + + # 创建数据库 + c1.execute('create database db') + c1.execute('use db') + # 建表 + c1.execute('create table tb (ts timestamp, temperature int, humidity float)') + # 插入数据 + start_time = datetime.datetime(2019, 11, 1) + affected_rows = c1.execute('insert into tb values (\'%s\', 0, 0.0)' %start_time) + # 批量插入数据 + time_interval = datetime.timedelta(seconds=60) + sqlcmd = ['insert into tb values'] + for irow in range(1,11): + start_time += time_interval + sqlcmd.append('(\'%s\', %d, %f)' %(start_time, irow, irow*1.2)) + affected_rows = c1.execute(' '.join(sqlcmd)) + ``` -* 从v2.1.0版本开始, 我们提供另外一种API:`connection.query` +4. 查询数据 ```python - import taos + c1.execute('select * from tb') + # 拉取查询结果 + data = c1.fetchall() + # 返回的结果是一个列表,每一行构成列表的一个元素 + numOfRows = c1.rowcount + numOfCols = len(c1.description) + for irow in range(numOfRows): + print("Row%d: ts=%s, temperature=%d, humidity=%f" %(irow, data[irow][0], data[irow][1], data[irow][2])) + + # 直接使用cursor 循环拉取查询结果 + c1.execute('select * from tb') + for data in c1: + print("ts=%s, temperature=%d, humidity=%f" %(data[0], data[1], data[2])) + ``` - conn = taos.connect() - conn.execute("create database if not exists pytest") +#### Query API - result = conn.query("show databases") - num_of_fields = result.field_count - for field in result.fields: - print(field) - for row in result: - print(row) - conn.execute("drop database pytest") - ``` +从v2.1.0版本开始, 我们提供另外一种方法:`connection.query` 来操作数据库。 - `query` 方法会返回一个 `TaosResult` 类对象,并提供了以下有用的属性或方法: +```python +import taos - 属性: +conn = taos.connect() +conn.execute("create database if not exists pytest") - - `fields`: `TaosFields` 集合类,提供返回数据的列信息。 - - `field_count`: 返回数据的列数. - - `affected_rows`: 插入数据的行数. - - `row_count`: 查询数据结果数. - - `precision`: 当前数据库的时间精度. +result = conn.query("show databases") +num_of_fields = result.field_count +for field in result.fields: + print(field) +for row in result: + print(row) +conn.execute("drop database pytest") +``` - 方法: +`query` 方法会返回一个 `TaosResult` 对象,并提供了以下属性或方法: - - `fetch_all()`: 类似于 `cursor.fetchall()` 返回同样的集合数据 - - `fetch_all_into_dict()`: v2.1.1 新添加的API,将上面的数据转换成字典类型返回 - - `blocks_iter()` `rows_iter()`: 根据底层API提供的两种不同迭代器。 - - `fetch_rows_a`: 异步API - - `errno`: 错误码 - - `errstr`: 错误信息 - - `close`: 关闭结果对象,一般不需要直接调用 +属性: +- `fields`: `TaosFields` 集合类,提供返回数据的列信息。 +- `field_count`: 返回数据的列数. +- `affected_rows`: 插入数据的行数. +- `row_count`: 查询数据结果数. +- `precision`: 当前数据库的时间精度. -* 创建订阅 +方法: -```python -# 创建一个主题为 'test' 消费周期为1000毫秒的订阅 -# 第一个参数为 True 表示重新开始订阅,如为 False 且之前创建过主题为 'test' 的订阅,则表示继续消费此订阅的数据,而不是重新开始消费所有数据 -sub = conn.subscribe(True, "test", "select * from tb;", 1000) -``` +- `fetch_all()`: 类似于 `cursor.fetchall()` 返回同样的集合数据 +- `fetch_all_into_dict()`: v2.1.1 新添加的API,将上面的数据转换成字典类型返回 +- `blocks_iter()` `rows_iter()`: 根据底层API提供的两种不同迭代器。 +- `fetch_rows_a`: 异步API +- `errno`: 错误码 +- `errstr`: 错误信息 +- `close`: 关闭结果对象,一般不需要直接调用 -* 消费订阅的数据 +#### 订阅 API -```python -data = sub.consume() -for d in data: - print(d) -``` +1. 创建一个同步订阅队列: -* 取消订阅 + ```python + # 创建一个主题为 'test' 消费周期为1000毫秒的订阅 + # 第一个参数为 True 表示重新开始订阅,如为 False 且之前创建过主题为 'test' 的订阅, + # 则表示继续消费此订阅的数据,而不是重新开始消费所有数据 + sub = conn.subscribe(True, "test", "select * from tb;", 1000) + ``` -```python -sub.close() -``` +2. 消费订阅的数据 -* 关闭连接 + ```python + data = sub.consume() + for d in data: + print(d) + ``` -```python -c1.close() -conn.close() -``` +3. 取消订阅 + + ```python + sub.close() + ``` + +4. 关闭连接 + + ```python + conn.close() + ``` #### 关于纳秒 (nanosecond) 在 Python 连接器中的说明 @@ -767,30 +760,20 @@ conn.close() 用户可通过python的帮助信息直接查看模块的使用信息,或者参考tests/examples/python中的示例程序。以下为部分常用类和方法: -- _TDengineConnection_ 类 +- _TaosConnection_ 类 - 参考python中help(taos.TDengineConnection)。 + 参考python中help(taos.TaosConnection)。 这个类对应客户端和TDengine建立的一个连接。在客户端多线程的场景下,推荐每个线程申请一个独立的连接实例,而不建议多线程共享一个连接。 -- _TDengineCursor_ 类 +- _TaosCursor_ 类 - 参考python中help(taos.TDengineCursor)。 + 参考python中help(taos.TaosCursor)。 这个类对应客户端进行的写入、查询操作。在客户端多线程的场景下,这个游标实例必须保持线程独享,不能跨线程共享使用,否则会导致返回结果出现错误。 - _connect_ 方法 - 用于生成taos.TDengineConnection的实例。 - -### Python客户端使用示例代码 + 用于生成taos.TaosConnection的实例。 -在tests/examples/python中,我们提供了一个示例Python程序read_example.py,可以参考这个程序来设计用户自己的写入、查询程序。在安装了对应的客户端后,通过import taos引入taos类。主要步骤如下 - -- 通过taos.connect获取TDengineConnection对象,这个对象可以一个程序只申请一个,在多线程中共享。 -- 通过TDengineConnection对象的 .cursor()方法获取一个新的游标对象,这个游标对象必须保证每个线程独享。 -- 通过游标对象的execute()方法,执行写入或查询的SQL语句。 -- 如果执行的是写入语句,execute返回的是成功写入的行数信息affected rows。 -- 如果执行的是查询语句,则execute执行成功后,需要通过fetchall方法去拉取结果集。 -具体方法可以参考示例代码。 ## RESTful Connector diff --git a/documentation20/en/08.connector/docs.md b/documentation20/en/08.connector/docs.md index b3b4dedabbbc55f554541710c4e0d8abd8e5c892..bc1197d2ed3c4c566e9618b505183123b1e31eb9 100644 --- a/documentation20/en/08.connector/docs.md +++ b/documentation20/en/08.connector/docs.md @@ -411,38 +411,22 @@ See [video tutorials](https://www.taosdata.com/blog/2020/11/11/1963.html) for th ### Python connector installation -#### Linux +From TDengine 2.4, users can install python connector for TDengine with `pip`. Note that the package name is **taospy** (not `taos` - a fully unrelated package). For backward compatibility, we still use `import taos` to import connector package. -Users can find the connector package for python2 and python3 in the source code src/connector/python (or tar.gz/connector/python) folder. Users can install it through `pip` command: - -`pip install src/connector/python/` - -or - - `pip3 install src/connector/python/` - -You can install the `taospy` connector from [PyPI](https://pypi.org/project/taospy/): - -```sh +```bash pip install taospy ``` -#### Windows +Use your version-specific `pip` command as if you need. -With Windows TDengine client installed, copy the file "C:\TDengine\driver\taos.dll" to the "C:\Windows\system32" directory and enter the Windows *cmd* command line interface: - -```cmd -cd C:\TDengine\connector\python -python -m pip install . +```bash +pip2 install taospy +pip3 install taospy ``` -Or install from PyPI: - -```cmd -pip install taospy -``` +The python connector requires `libtaos` library (`libtaos.so` in Linux, or `taos.dll` in Windows). For Windows client, if `import taos` failed, you could copy the dll `C:\TDengine\driver\taos.dll` to `C:\windows\system32` and try it again. -- If there is no `pip` command on the machine, the user can copy the taos folder under src/connector/python to the application directory for use. For Windows client, after installing the TDengine Windows client, copy C:\ TDengine\driver\taos.dll to the C:\ windows\ system32 directory. +For users that has a limited network environment, just add the `connector/python` of installed directory(commonly `/usr/local/taos/connector/python/` in Linux, `C:\TDengine\connector\python` in Windows) to `PYTHONPATH` environment variable. ### How to use @@ -462,63 +446,66 @@ for row in results: print(row) ``` -#### Code sample +##### Code sample - Import the TDengine client module -```python -import taos -``` + ```python + import taos + ``` - Get the connection and cursor object -```python -conn = taos.connect(host="127.0.0.1", user="root", password="taosdata", config="/etc/taos") -c1 = conn.cursor() -``` + ```python + conn = taos.connect(host="127.0.0.1", user="root", password="taosdata", config="/etc/taos") + c1 = conn.cursor() + ``` + + *host* covers all IPs of TDengine server-side, and *config* is the directory where the client configuration files is located -- *host* covers all IPs of TDengine server-side, and *config* is the directory where the client configuration files is located - Write data -```python -import datetime - -# Create a database -c1.execute('create database db') -c1.execute('use db') -# Create a table -c1.execute('create table tb (ts timestamp, temperature int, humidity float)') -# Insert data -start_time = datetime.datetime(2019, 11, 1) -affected_rows = c1.execute('insert into tb values (\'%s\', 0, 0.0)' %start_time) -# Insert data in batch -time_interval = datetime.timedelta(seconds=60) -sqlcmd = ['insert into tb values'] -for irow in range(1,11): - start_time += time_interval - sqlcmd.append('(\'%s\', %d, %f)' %(start_time, irow, irow*1.2)) -affected_rows = c1.execute(' '.join(sqlcmd)) -``` + ```python + import datetime + + # Create a database + c1.execute('create database db') + c1.execute('use db') + # Create a table + c1.execute('create table tb (ts timestamp, temperature int, humidity float)') + # Insert data + start_time = datetime.datetime(2019, 11, 1) + affected_rows = c1.execute('insert into tb values (\'%s\', 0, 0.0)' %start_time) + # Insert data in batch + time_interval = datetime.timedelta(seconds=60) + sqlcmd = ['insert into tb values'] + for irow in range(1,11): + start_time += time_interval + sqlcmd.append('(\'%s\', %d, %f)' %(start_time, irow, irow*1.2)) + affected_rows = c1.execute(' '.join(sqlcmd)) + ``` - Query data -```python -c1.execute('select * from tb') -# pull query result -data = c1.fetchall() -# The result is a list, with each row as an element -numOfRows = c1.rowcount -numOfCols = len(c1.description) -for irow in range(numOfRows): - print("Row%d: ts=%s, temperature=%d, humidity=%f" %(irow, data[irow][0], data[irow][1],data[irow][2])) - -# Use cursor loop directly to pull query result -c1.execute('select * from tb') -for data in c1: - print("ts=%s, temperature=%d, humidity=%f" %(data[0], data[1],data[2])) -``` + ```python + c1.execute('select * from tb') + # pull query result + data = c1.fetchall() + # The result is a list, with each row as an element + numOfRows = c1.rowcount + numOfCols = len(c1.description) + for irow in range(numOfRows): + print("Row%d: ts=%s, temperature=%d, humidity=%f" %(irow, data[irow][0], data[irow][1],data[irow][2])) + + # Use cursor loop directly to pull query result + c1.execute('select * from tb') + for data in c1: + print("ts=%s, temperature=%d, humidity=%f" %(data[0], data[1],data[2])) + ``` -- Since v2.1.0, python connector provides a new API for query: +#### Query API + +Since v2.1.0, python connector provides a new API for query: ```python import taos @@ -556,15 +543,19 @@ Functions: - `errstr`: error string if failed. - `close`: close result, you do not need to call it directly, result will auto closed out of scope. -- Create subscription +#### Subscription API + +Create subscription ```python # Create a subscription with the topic ‘test’ and a consumption cycle of 1000 milliseconds -# If the first parameter is True, it means restarting the subscription. If it is False and a subscription with the topic 'test 'has been created before, it means continuing to consume the data of this subscription instead of restarting to consume all the data +# If the first parameter is True, it means restarting the subscription. +# If it is False and a subscription with the topic 'test 'has been created before, +# it means continuing to consume the data of this subscription instead of restarting to consume all the data sub = conn.subscribe(True, "test", "select * from tb;", 1000) ``` -- Consume subscription data +Consume subscription data. ```python data = sub.consume() @@ -572,17 +563,15 @@ for d in data: print(d) ``` -- Unsubscription +Unsubscribe. ```python sub.close() ``` - -- Close connection +Close connection. ```python -c1.close() conn.close() ``` diff --git a/src/client/src/tscSQLParser.c b/src/client/src/tscSQLParser.c index 3032b27b9cab6005d9cde120ede7fde831df181f..955eaa32f058931618a11885a30bfa4645a2e4eb 100644 --- a/src/client/src/tscSQLParser.c +++ b/src/client/src/tscSQLParser.c @@ -1092,7 +1092,7 @@ static int32_t addPrimaryTsColumnForTimeWindowQuery(SQueryInfo* pQueryInfo, SSql tstrncpy(s.name, aAggs[TSDB_FUNC_TS].name, sizeof(s.name)); SColumnIndex index = {tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - tscAddFuncInSelectClause(pQueryInfo, 0, TSDB_FUNC_TS, &index, &s, TSDB_COL_NORMAL, getNewResColId(pCmd)); + tscAddFuncInSelectClause(pQueryInfo, 0, TSDB_FUNC_TS, &index, &s, TSDB_COL_NORMAL, 0); return TSDB_CODE_SUCCESS; } @@ -2191,7 +2191,7 @@ int32_t validateSelectNodeList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SArray* pS return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg11); } - if(pItem->aliasName != NULL && validateColumnName(pItem->aliasName) != TSDB_CODE_SUCCESS){ + if(pItem->aliasName != NULL && strcasecmp(pItem->aliasName, DEFAULT_PRIMARY_TIMESTAMP_COL_NAME) == 0){ return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg11); } @@ -2774,12 +2774,17 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3); } + pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex); + SSchema* pColumnSchema = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, index.columnIndex); + // elapsed only can be applied to primary key - if (functionId == TSDB_FUNC_ELAPSED && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) { - return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "elapsed only can be applied to primary key"); + if (functionId == TSDB_FUNC_ELAPSED) { + if ( index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX || pColumnSchema->colId != PRIMARYKEY_TIMESTAMP_COL_INDEX) { + return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), "elapsed only can be applied to primary key"); + } } - pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex); + STableComInfo info = tscGetTableInfo(pTableMetaInfo->pTableMeta); // functions can not be applied to tags @@ -2809,7 +2814,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col if (functionId == TSDB_FUNC_DIFF || functionId == TSDB_FUNC_DERIVATIVE || functionId == TSDB_FUNC_CSUM) { SColumnIndex indexTS = {.tableIndex = index.tableIndex, .columnIndex = 0}; SExprInfo* pExpr = tscExprAppend(pQueryInfo, TSDB_FUNC_TS_DUMMY, &indexTS, TSDB_DATA_TYPE_TIMESTAMP, - TSDB_KEYSIZE, getNewResColId(pCmd), TSDB_KEYSIZE, false); + TSDB_KEYSIZE, 0, TSDB_KEYSIZE, false); tstrncpy(pExpr->base.aliasName, aAggs[TSDB_FUNC_TS_DUMMY].name, sizeof(pExpr->base.aliasName)); SColumnList ids = createColumnList(1, 0, 0); @@ -3130,7 +3135,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col // set the first column ts for top/bottom query int32_t tsFuncId = (functionId == TSDB_FUNC_MAVG) ? TSDB_FUNC_TS_DUMMY : TSDB_FUNC_TS; SColumnIndex index1 = {index.tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - pExpr = tscExprAppend(pQueryInfo, tsFuncId, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, getNewResColId(pCmd), + pExpr = tscExprAppend(pQueryInfo, tsFuncId, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, 0, 0, false); tstrncpy(pExpr->base.aliasName, aAggs[tsFuncId].name, sizeof(pExpr->base.aliasName)); @@ -3156,7 +3161,7 @@ int32_t addExprAndResultField(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, int32_t col // todo REFACTOR // set the first column ts for top/bottom query SColumnIndex index1 = {index.tableIndex, PRIMARYKEY_TIMESTAMP_COL_INDEX}; - pExpr = tscExprAppend(pQueryInfo, TSDB_FUNC_TS, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, getNewResColId(pCmd), + pExpr = tscExprAppend(pQueryInfo, TSDB_FUNC_TS, &index1, TSDB_DATA_TYPE_TIMESTAMP, TSDB_KEYSIZE, 0, 0, false); tstrncpy(pExpr->base.aliasName, aAggs[TSDB_FUNC_TS].name, sizeof(pExpr->base.aliasName)); diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index 4879576bc447b0f483a641b749dbc4b9fc5218e2..c72dfd105e410a290e19d4c20db9339fdb09d1f3 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -837,7 +837,7 @@ static int32_t serializeSqlExpr(SSqlExpr* pExpr, STableMetaInfo* pTableMetaInfo, return TSDB_CODE_TSC_INVALID_OPERATION; } - if (pExpr->resColId >= 0) { + if (pExpr->resColId > 0) { tscError("result column id underflowed: %d", pExpr->resColId); return TSDB_CODE_TSC_RES_TOO_MANY; } diff --git a/src/connector/C#/.gitignore b/src/connector/C#/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..525c7a04c07762c6f77bdaaaf7d602a5b4fc9591 --- /dev/null +++ b/src/connector/C#/.gitignore @@ -0,0 +1,6 @@ +src/TDengineDriver/bin/ +src/TDengineDriver/obj/ +src/test/Cases/bin/ +src/test/Cases/obj/ +src/test/XUnitTest/bin/ +src/test/XUnitTest/obj/ diff --git a/src/connector/C#/src/TDengineDriver/TDengineDriver.cs b/src/connector/C#/src/TDengineDriver/TDengineDriver.cs index 1bfb8eae0729f9d5d68734209cb4cc5ef36d8c6a..42bba438522db2a1c238609036e2b5be8b37929f 100644 --- a/src/connector/C#/src/TDengineDriver/TDengineDriver.cs +++ b/src/connector/C#/src/TDengineDriver/TDengineDriver.cs @@ -35,7 +35,8 @@ namespace TDengineDriver TSDB_DATA_TYPE_UTINYINT = 11,// 1 byte TSDB_DATA_TYPE_USMALLINT = 12,// 2 bytes TSDB_DATA_TYPE_UINT = 13, // 4 bytes - TSDB_DATA_TYPE_UBIGINT = 14 // 8 bytes + TSDB_DATA_TYPE_UBIGINT = 14, // 8 bytes + TSDB_DATA_TYPE_JSONTAG = 15 //4096 bytes } public enum TDengineInitOption @@ -46,7 +47,6 @@ namespace TDengineDriver TDDB_OPTION_CONFIGDIR = 3, TDDB_OPTION_SHELL_ACTIVITY_TIMER = 4 } - enum TaosField { STRUCT_SIZE = 68, @@ -92,6 +92,8 @@ namespace TDengineDriver return "TIMESTAMP"; case TDengineDataType.TSDB_DATA_TYPE_NCHAR: return "NCHAR"; + case TDengineDataType.TSDB_DATA_TYPE_JSONTAG: + return "JSON"; default: return "undefine"; } @@ -204,6 +206,7 @@ namespace TDengineDriver metas.Add(meta); } + return metas; } diff --git a/src/connector/C#/src/test/Cases/JsonTag.cs b/src/connector/C#/src/test/Cases/JsonTag.cs new file mode 100644 index 0000000000000000000000000000000000000000..a079919c13989cbaf0a3447bbf4f1626ca32d22f --- /dev/null +++ b/src/connector/C#/src/test/Cases/JsonTag.cs @@ -0,0 +1,349 @@ +using System; +using Test.UtilsTools; + +namespace Cases +{ + public class JsonTagTest + { + public void Test(IntPtr conn) + { + Console.WriteLine("STEP 1 prepare data & validate json string===== "); + UtilsTools.ExecuteQuery(conn, "create table if not exists jsons1(ts timestamp, dataInt int, dataBool bool, dataStr nchar(50), dataStrBin binary(150)) tags(jtag json)"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_1 using jsons1 tags('{\"tag1\":\"fff\",\"tag2\":5, \"tag3\":true}') values(1591060618000, 1, false, 'json1', '涛思数据') (1591060608000, 23, true, '涛思数据', 'json')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_2 using jsons1 tags('{\"tag1\":5,\"tag2\":\"beijing\"}') values (1591060628000, 2, true, 'json2', 'sss')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_3 using jsons1 tags('{\"tag1\":false,\"tag2\":\"beijing\"}') values (1591060668000, 3, false, 'json3', 'efwe')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_4 using jsons1 tags('{\"tag1\":null,\"tag2\":\"shanghai\",\"tag3\":\"hello\"}') values (1591060728000, 4, true, 'json4', '323sd')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_5 using jsons1 tags('{\"tag1\":1.232, \"tag2\":null}') values(1591060928000, 1, false, '涛思数据', 'ewe')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_6 using jsons1 tags('{\"tag1\":11,\"tag2\":\"\",\"tag2\":null}') values(1591061628000, 11, false, '涛思数据','')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_7 using jsons1 tags('{\"tag1\":\"涛思数据\",\"tag2\":\"\",\"tag3\":null}') values(1591062628000, 2, NULL, '涛思数据', 'dws')"); + Console.WriteLine(""); + + Console.WriteLine("test duplicate key using the first one. elimate empty key======== "); + UtilsTools.ExecuteQuery(conn, "CREATE TABLE if not exists jsons1_8 using jsons1 tags('{\"tag1\":null, \"tag1\":true, \"tag1\":45, \"1tag$\":2, \" \":90}')"); + Console.WriteLine(""); + + Console.WriteLine("test empty json string, save as jtag is NULL========== "); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_9 using jsons1 tags('\t') values (1591062328000, 24, NULL, '涛思数据', '2sdw')"); + UtilsTools.ExecuteQuery(conn, "CREATE TABLE if not exists jsons1_10 using jsons1 tags('')"); + UtilsTools.ExecuteQuery(conn, "CREATE TABLE if not exists jsons1_11 using jsons1 tags(' ')"); + UtilsTools.ExecuteQuery(conn, "CREATE TABLE if not exists jsons1_12 using jsons1 tags('{}')"); + UtilsTools.ExecuteQuery(conn, "CREATE TABLE if not exists jsons1_13 using jsons1 tags('null')"); + Console.WriteLine(""); + + Console.WriteLine("test invalidate json==================== "); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('\"efwewf\"')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('3333')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('33.33')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('false')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('[1,true]')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{222}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"fe\"}')"); + Console.WriteLine(""); + + Console.WriteLine("test invalidate json key, key must can be printed assic char========== "); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"tag1\":[1,true]}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"tag1\":{}}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"。loc\":\"fff\"}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"\":\"fff\"}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"\t\":\"fff\"}')"); + UtilsTools.ExecuteErrorQuery(conn, "CREATE TABLE if not exists jsons1_14 using jsons1 tags('{\"试试\":\"fff\"}')"); + Console.WriteLine(""); + + Console.WriteLine("STEP 2 alter table json tag============"); + UtilsTools.ExecuteErrorQuery(conn, "ALTER STABLE jsons1 add tag tag2 nchar(20)"); + UtilsTools.ExecuteErrorQuery(conn, "ALTER STABLE jsons1 drop tag jtag"); + UtilsTools.ExecuteErrorQuery(conn, "ALTER TABLE jsons1_1 SET TAG jtag=4"); + UtilsTools.ExecuteQuery(conn, "ALTER TABLE jsons1_1 SET TAG jtag='{\"tag1\":\"femail\",\"tag2\":35,\"tag3\":true}'"); + Console.WriteLine(""); + + Console.WriteLine("STEP 3 query table============"); + Console.WriteLine("test error syntax============"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->tag1='beijing'"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'location'"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->''"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->''=9"); + UtilsTools.ExecuteErrorQuery(conn, "select -> from jsons1"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where contains"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->"); + UtilsTools.ExecuteErrorQuery(conn, "select jtag->location from jsons1"); + UtilsTools.ExecuteErrorQuery(conn, "select jtag contains location from jsons1"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag contains location"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag contains''"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag contains 'location'='beijing'"); + Console.WriteLine(""); + + Console.WriteLine("test select normal column==========="); + IntPtr res = IntPtr.Zero; + res = UtilsTools.ExecuteQuery(conn, "select dataint from jsons1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1 where jtag is null"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1 where jtag is not null"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test #line 41==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1_8"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test #line 72==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1_1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test jtag is NULL==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag from jsons1_9"); + UtilsTools.DisplayRes(res); + + + Console.WriteLine("test select json tag->'key', value is string ==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from jsons1_1"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag2' from jsons1_6"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag->'key', value is int==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag2' from jsons1_1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag->'key', value is bool==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag3' from jsons1_1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag->'key', value is null==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from jsons1_4"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag->'key', value is double==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from jsons1_5"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test select json tag->'key', key is not exist==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag10' from jsons1_4"); + UtilsTools.DisplayRes(res); + + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from jsons1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test header name==========="); + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from jsons1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test where with json tag==========="); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1_1 where jtag is not null"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag='{\"tag1\":11,\"tag2\":\"\"}'"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'tag1'={}"); + + Console.WriteLine("where json value is string==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select dataint,tbname,jtag->'tag1',jtag from jsons1 where jtag->'tag2'='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'='涛思数据'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'>'beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'>='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'<'beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'<='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'!='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2'=''"); + UtilsTools.DisplayRes(res); + + + Console.WriteLine("where json value is int==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=5"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=10"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'<54"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'<=11"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'>4"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'>=5"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'!=5"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'!=55"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("where json value is double==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=1.232"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'<1.232"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'<=1.232"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'>1.23"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'>=1.232"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'!=1.232"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'!=3.232"); + UtilsTools.DisplayRes(res); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'tag1'/0=3"); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'tag1'/5=1"); + + Console.WriteLine("where json value is bool==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=true"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=false"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'!=false"); + UtilsTools.DisplayRes(res); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'tag1'>false"); + + Console.WriteLine("where json value is null==========="); + Console.WriteLine("only json suport =null. This synatx will change later.==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=null"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("where json is null==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag is null"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag is not null"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("where json key is null==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag_no_exist'=3"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("where json value is not exist==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1' is null"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag4' is null"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag3' is not null"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test contains==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag contains 'tag1'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag contains 'tag3'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag contains 'tag_no_exist'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test json tag in where condition with and/or==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=false and jtag->'tag2'='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=false or jtag->'tag2'='beijing'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=false and jtag->'tag2'='shanghai'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=false and jtag->'tag2'='shanghai'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=13 or jtag->'tag2'>35"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'=13 or jtag->'tag2'>35"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1' is not null and jtag contains 'tag3'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1'='femail' and jtag contains 'tag3'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test with tbname/normal column==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where tbname = 'jsons1_1'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where tbname = 'jsons1_1' and jtag contains 'tag3'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where tbname = 'jsons1_1' and jtag contains 'tag3' and dataint=3"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where tbname = 'jsons1_1' and jtag contains 'tag3' and dataint=23"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test where condition like==========="); + res = UtilsTools.ExecuteQuery(conn, "select *,tbname from jsons1 where jtag->'tag2' like 'bei%'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select *,tbname from jsons1 where jtag->'tag1' like 'fe%' and jtag->'tag2' is not null"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test where condition in no support in==========="); + UtilsTools.ExecuteErrorQuery(conn, "select * from jsons1 where jtag->'tag1' in ('beijing')"); + + Console.WriteLine("test where condition match==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1' match 'ma'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1' match 'ma$'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag2' match 'jing$'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select * from jsons1 where jtag->'tag1' match '收到'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test distinct==========="); + UtilsTools.ExecuteQuery(conn, "insert into jsons1_14 using jsons1 tags('{\"tag1\":\"涛思数据\",\"tag2\":\"\",\"tag3\":null}') values(1591062628000, 2, NULL, '涛思数据', 'dws')"); + res = UtilsTools.ExecuteQuery(conn, "select distinct jtag->'tag1' from jsons1"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select distinct jtag from jsons1"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test dumplicate key with normal colomn==========="); + UtilsTools.ExecuteQuery(conn, "INSERT INTO jsons1_15 using jsons1 tags('{\"tbname\":\"tt\",\"databool\":true,\"datastr\":\"涛思数据\"}') values(1591060828000, 4, false, 'jjsf', \"你就会\")"); + res = UtilsTools.ExecuteQuery(conn, "select *,tbname,jtag from jsons1 where jtag->'datastr' match '涛思数据' and datastr match 'js'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select tbname,jtag->'tbname' from jsons1 where jtag->'tbname'='tt' and tbname='jsons1_14'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test join==========="); + UtilsTools.ExecuteQuery(conn, "create table if not exists jsons2(ts timestamp, dataInt int, dataBool bool, dataStr nchar(50), dataStrBin binary(150)) tags(jtag json)"); + UtilsTools.ExecuteQuery(conn, "insert into jsons2_1 using jsons2 tags('{\"tag1\":\"fff\",\"tag2\":5, \"tag3\":true}') values(1591060618000, 2, false, 'json2', '涛思数据2')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons2_2 using jsons2 tags('{\"tag1\":5,\"tag2\":null}') values (1591060628000, 2, true, 'json2', 'sss')"); + UtilsTools.ExecuteQuery(conn, "create table if not exists jsons3(ts timestamp, dataInt int, dataBool bool, dataStr nchar(50), dataStrBin binary(150)) tags(jtag json)"); + UtilsTools.ExecuteQuery(conn, "insert into jsons3_1 using jsons3 tags('{\"tag1\":\"fff\",\"tag2\":5, \"tag3\":true}') values(1591060618000, 3, false, 'json3', '涛思数据3')"); + UtilsTools.ExecuteQuery(conn, "insert into jsons3_2 using jsons3 tags('{\"tag1\":5,\"tag2\":\"beijing\"}') values (1591060638000, 2, true, 'json3', 'sss')"); + + res = UtilsTools.ExecuteQuery(conn, "select 'sss',33,a.jtag->'tag3' from jsons2 a,jsons3 b where a.ts=b.ts and a.jtag->'tag1'=b.jtag->'tag1'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select 'sss',33,a.jtag->'tag3' from jsons2 a,jsons3 b where a.ts=b.ts and a.jtag->'tag1'=b.jtag->'tag1'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test group by & order by json tag==========="); + res = UtilsTools.ExecuteQuery(conn, "select count(*) from jsons1 group by jtag->'tag1' order by jtag->'tag1' desc"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select count(*) from jsons1 group by jtag->'tag1' order by jtag->'tag1' asc"); + UtilsTools.DisplayRes(res); + + + Console.WriteLine("test stddev with group by json tag==========="); + res = UtilsTools.ExecuteQuery(conn, "select stddev(dataint) from jsons1 group by jtag->'tag1'"); + UtilsTools.DisplayRes(res); + res = UtilsTools.ExecuteQuery(conn, "select stddev(dataint) from jsons1 group by jsons1.jtag->'tag1'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("test top/bottom with group by json tag==========="); + res = UtilsTools.ExecuteQuery(conn, "select top(dataint,100) from jsons1 group by jtag->'tag1'"); + UtilsTools.DisplayRes(res); + + Console.WriteLine("subquery with json tag==========="); + res = UtilsTools.ExecuteQuery(conn, "select * from (select jtag, dataint from jsons1)"); + UtilsTools.DisplayRes(res); + + + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from (select jtag->'tag1', dataint from jsons1)"); + UtilsTools.DisplayRes(res); + + res = UtilsTools.ExecuteQuery(conn, "select jtag->'tag1' from (select jtag->'tag1', dataint from jsons1)"); + UtilsTools.DisplayRes(res); + + res = UtilsTools.ExecuteQuery(conn, "select ts,tbname,jtag->'tag1' from (select jtag->'tag1',tbname,ts from jsons1 order by ts)"); + UtilsTools.DisplayRes(res); + Console.WriteLine(""); + + + } + } +} \ No newline at end of file diff --git a/src/connector/C#/src/test/Cases/Program.cs b/src/connector/C#/src/test/Cases/Program.cs index 3d3b765b5bfb80c61b85d974bcc240d7a234d75d..a1b47f3890134040d3060fdb7b1e8d3beed4b7dd 100644 --- a/src/connector/C#/src/test/Cases/Program.cs +++ b/src/connector/C#/src/test/Cases/Program.cs @@ -1,59 +1,64 @@ -using System; -using Test.UtilsTools; -using Cases; - -namespace Cases.EntryPoint -{ - class Program - { - - static void Main(string[] args) - { - IntPtr conn = IntPtr.Zero; - IntPtr stmt = IntPtr.Zero; - IntPtr res = IntPtr.Zero; - - conn = UtilsTools.TDConnection("127.0.0.1", "root", "taosdata", "", 0); - UtilsTools.ExecuteQuery(conn, "drop database if exists csharp"); - UtilsTools.ExecuteQuery(conn, "create database if not exists csharp keep 3650"); - UtilsTools.ExecuteQuery(conn, "use csharp"); - - Console.WriteLine("====================StableColumnByColumn==================="); - StableColumnByColumn columnByColumn = new StableColumnByColumn(); - columnByColumn.Test(conn, "stablecolumnbycolumn"); - Console.WriteLine("====================StmtStableQuery==================="); - StmtStableQuery stmtStableQuery = new StmtStableQuery(); - stmtStableQuery.Test(conn, "stablecolumnbycolumn"); - - Console.WriteLine("====================StableMutipleLine==================="); - StableMutipleLine mutipleLine = new StableMutipleLine(); - mutipleLine.Test(conn, "stablemutipleline"); - - //================================================================================ - - Console.WriteLine("====================NtableSingleLine==================="); - NtableSingleLine ntableSingleLine = new NtableSingleLine(); - ntableSingleLine.Test(conn, "stablesingleline"); - - Console.WriteLine("====================NtableMutipleLine==================="); - NtableMutipleLine ntableMutipleLine = new NtableMutipleLine(); - ntableMutipleLine.Test(conn, "ntablemutipleline"); - Console.WriteLine("====================StmtNtableQuery==================="); - StmtNtableQuery stmtNtableQuery = new StmtNtableQuery(); - stmtNtableQuery.Test(conn, "ntablemutipleline"); - - Console.WriteLine("====================NtableColumnByColumn==================="); - NtableColumnByColumn ntableColumnByColumn = new NtableColumnByColumn(); - ntableColumnByColumn.Test(conn, "ntablecolumnbycolumn"); - - Console.WriteLine("====================fetchfeilds==================="); - FetchFields fetchFields = new FetchFields(); - fetchFields.Test(conn, "fetchfeilds"); - - UtilsTools.ExecuteQuery(conn, "drop database if exists csharp"); - UtilsTools.CloseConnection(conn); - UtilsTools.ExitProgram(); - - } - } -} +using System; +using Test.UtilsTools; +using Cases; + +namespace Cases.EntryPoint +{ + class Program + { + + static void Main(string[] args) + { + IntPtr conn = IntPtr.Zero; + IntPtr stmt = IntPtr.Zero; + IntPtr res = IntPtr.Zero; + + conn = UtilsTools.TDConnection("127.0.0.1", "root", "taosdata", "", 0); + UtilsTools.ExecuteQuery(conn, "drop database if exists csharp"); + UtilsTools.ExecuteQuery(conn, "create database if not exists csharp keep 3650"); + UtilsTools.ExecuteQuery(conn, "use csharp"); + + Console.WriteLine("====================StableColumnByColumn==================="); + StableColumnByColumn columnByColumn = new StableColumnByColumn(); + columnByColumn.Test(conn, "stablecolumnbycolumn"); + Console.WriteLine("====================StmtStableQuery==================="); + StmtStableQuery stmtStableQuery = new StmtStableQuery(); + stmtStableQuery.Test(conn, "stablecolumnbycolumn"); + + Console.WriteLine("====================StableMutipleLine==================="); + StableMutipleLine mutipleLine = new StableMutipleLine(); + mutipleLine.Test(conn, "stablemutipleline"); + + //================================================================================ + + Console.WriteLine("====================NtableSingleLine==================="); + NtableSingleLine ntableSingleLine = new NtableSingleLine(); + ntableSingleLine.Test(conn, "stablesingleline"); + + Console.WriteLine("====================NtableMutipleLine==================="); + NtableMutipleLine ntableMutipleLine = new NtableMutipleLine(); + ntableMutipleLine.Test(conn, "ntablemutipleline"); + Console.WriteLine("====================StmtNtableQuery==================="); + StmtNtableQuery stmtNtableQuery = new StmtNtableQuery(); + stmtNtableQuery.Test(conn, "ntablemutipleline"); + + Console.WriteLine("====================NtableColumnByColumn==================="); + NtableColumnByColumn ntableColumnByColumn = new NtableColumnByColumn(); + ntableColumnByColumn.Test(conn, "ntablecolumnbycolumn"); + + Console.WriteLine("====================fetchfeilds==================="); + FetchFields fetchFields = new FetchFields(); + fetchFields.Test(conn,"fetchfeilds"); + + Console.WriteLine("===================JsonTagTest===================="); + JsonTagTest jsonTagTest = new JsonTagTest(); + jsonTagTest.Test(conn); + + // UtilsTools.ExecuteQuery(conn, "drop database if exists csharp"); + UtilsTools.CloseConnection(conn); + UtilsTools.ExitProgram(); + + + } + } +} diff --git a/src/connector/C#/src/test/Cases/TaosFeild.cs b/src/connector/C#/src/test/Cases/TaosFeild.cs index b8c6d37ef5e3f14640d5e87504148c4ea7748e23..ce272e2d55d5803730df1408e65a8f1d8808a04b 100644 --- a/src/connector/C#/src/test/Cases/TaosFeild.cs +++ b/src/connector/C#/src/test/Cases/TaosFeild.cs @@ -1,37 +1,39 @@ -using System; -using Test.UtilsTools; -using TDengineDriver; -using System.Collections.Generic; -using System.Runtime.InteropServices; -namespace Cases -{ - public class FetchFields - { - public void Test(IntPtr conn, string tableName) - { - IntPtr res = IntPtr.Zero; - String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(id int);"; - String insertSql = "insert into " + tableName + "_t1 using " + tableName + " tags(1) values(1637064040000,true,1,2,3,4,5,6,7,8,9,10,'XI','XII')"; - String selectSql = "select * from " + tableName; - String dropSql = "drop table " + tableName; - UtilsTools.ExecuteQuery(conn, createTb); - UtilsTools.ExecuteQuery(conn, insertSql); - res = UtilsTools.ExecuteQuery(conn, selectSql); - UtilsTools.ExecuteQuery(conn, dropSql); - - List metas = new List(); - metas = TDengine.FetchFields(res); - if (metas.Capacity == 0) - { - Console.WriteLine("empty result"); - } - else - { - foreach(TDengineMeta meta in metas){ - Console.WriteLine("col_name:{0},col_type_code:{1},col_type:{2}({3})",meta.name,meta.type,meta.TypeName(),meta.size); - } - } - - } - } -} \ No newline at end of file +using System; +using Test.UtilsTools; +using TDengineDriver; +using System.Collections.Generic; +using System.Runtime.InteropServices; +namespace Cases +{ + public class FetchFields + { + public void Test(IntPtr conn, string tableName) + { + IntPtr res = IntPtr.Zero; + String createTb = "create stable " + tableName + " (ts timestamp ,b bool,v1 tinyint,v2 smallint,v4 int,v8 bigint,f4 float,f8 double,u1 tinyint unsigned,u2 smallint unsigned,u4 int unsigned,u8 bigint unsigned,bin binary(200),blob nchar(200))tags(jsontag json);"; + String insertSql = "insert into " + tableName + "_t1 using " + tableName + " tags('{\"k1\": \"v1\"}') values(1637064040000,true,1,2,3,4,5,6,7,8,9,10,'XI','XII')"; + String selectSql = "select * from " + tableName; + String dropSql = "drop table " + tableName; + UtilsTools.ExecuteQuery(conn, createTb); + UtilsTools.ExecuteQuery(conn, insertSql); + res = UtilsTools.ExecuteQuery(conn, selectSql); + UtilsTools.ExecuteQuery(conn, dropSql); + + List metas = new List(); + metas = TDengine.FetchFields(res); + if (metas.Capacity == 0) + { + Console.WriteLine("empty result"); + } + else + { + foreach(TDengineMeta meta in metas){ + Console.WriteLine("col_name:{0},col_type_code:{1},col_type:{2}({3})",meta.name,meta.type,meta.TypeName(),meta.size); + } + } + + } + } +} + + diff --git a/src/connector/C#/src/test/Cases/Utils.cs b/src/connector/C#/src/test/Cases/Utils.cs index 5a2962564fb9063e8994e549f0135cedb36b6ec5..a549d75b16f76539b0f19d73eab576d0d9d582db 100644 --- a/src/connector/C#/src/test/Cases/Utils.cs +++ b/src/connector/C#/src/test/Cases/Utils.cs @@ -39,6 +39,28 @@ namespace Test.UtilsTools } return res; } + + public static IntPtr ExecuteErrorQuery(IntPtr conn, String sql) + { + IntPtr res = TDengine.Query(conn, sql); + if ((res == IntPtr.Zero) || (TDengine.ErrorNo(res) != 0)) + { + Console.Write(sql.ToString() + " failure, "); + if (res != IntPtr.Zero) + { + Console.Write("reason: " + TDengine.Error(res)); + + } + Console.WriteLine(""); + } + else + { + Console.WriteLine(sql.ToString() + " success"); + + } + return res; + } + public static void DisplayRes(IntPtr res) { long queryRows = 0; @@ -120,6 +142,10 @@ namespace Test.UtilsTools string v10 = Marshal.PtrToStringAnsi(data); builder.Append(v10); break; + case TDengineDataType.TSDB_DATA_TYPE_JSONTAG: + string v11 = Marshal.PtrToStringAnsi(data); + builder.Append(v11); + break; } } builder.Append("---"); diff --git a/src/connector/nodejs/.gitignore b/src/connector/nodejs/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..d8b83df9cdb661545c4f6d15a299e6e1f1f51dc4 --- /dev/null +++ b/src/connector/nodejs/.gitignore @@ -0,0 +1 @@ +package-lock.json diff --git a/src/kit/taos-tools b/src/kit/taos-tools index dca4059d87c3f5c678a5e946978d40daec204e27..beca4813316f254624d8dbecf54d45a5a232c61d 160000 --- a/src/kit/taos-tools +++ b/src/kit/taos-tools @@ -1 +1 @@ -Subproject commit dca4059d87c3f5c678a5e946978d40daec204e27 +Subproject commit beca4813316f254624d8dbecf54d45a5a232c61d diff --git a/src/os/inc/osAtomic.h b/src/os/inc/osAtomic.h index 7affa444ee44c8c7e6de209f2b4ea23238c26d3b..d15f5aeb739fec9aea102aa12368da9751240454 100644 --- a/src/os/inc/osAtomic.h +++ b/src/os/inc/osAtomic.h @@ -36,7 +36,11 @@ extern "C" { #define atomic_exchange_8(ptr, val) _InterlockedExchange8((char volatile*)(ptr), (char)(val)) #define atomic_exchange_16(ptr, val) _InterlockedExchange16((short volatile*)(ptr), (short)(val)) #define atomic_exchange_32(ptr, val) _InterlockedExchange((long volatile*)(ptr), (long)(val)) +#if _MSC_VER >= 1930 + #define atomic_exchange_64(ptr, val) InterlockedExchange64((__int64 volatile*)(ptr), (__int64)(val)) +#else #define atomic_exchange_64(ptr, val) _InterlockedExchange64((__int64 volatile*)(ptr), (__int64)(val)) +#endif #ifdef _WIN64 #define atomic_exchange_ptr(ptr, val) _InterlockedExchangePointer((void* volatile*)(ptr), (void*)(val)) #else @@ -91,7 +95,12 @@ extern "C" { #define atomic_fetch_add_8(ptr, val) _InterlockedExchangeAdd8((char volatile*)(ptr), (char)(val)) #define atomic_fetch_add_16(ptr, val) _InterlockedExchangeAdd16((short volatile*)(ptr), (short)(val)) #define atomic_fetch_add_32(ptr, val) _InterlockedExchangeAdd((long volatile*)(ptr), (long)(val)) + +#if _MSC_VER >= 1930 + #define atomic_fetch_add_64(ptr, val) InterlockedExchangeAdd64((__int64 volatile*)(ptr), (__int64)(val)) +#else #define atomic_fetch_add_64(ptr, val) _InterlockedExchangeAdd64((__int64 volatile*)(ptr), (__int64)(val)) +#endif #define atomic_sub_fetch_8(ptr, val) interlocked_add_fetch_8((char volatile*)(ptr), -(char)(val)) #define atomic_sub_fetch_16(ptr, val) interlocked_add_fetch_16((short volatile*)(ptr), -(short)(val)) diff --git a/src/os/src/detail/osTime.c b/src/os/src/detail/osTime.c index a76010b37f4dec456d1be1134efbf6153451f911..7dfa2b0217517bcf5f913ed9bcf10b46252d21ec 100644 --- a/src/os/src/detail/osTime.c +++ b/src/os/src/detail/osTime.c @@ -121,7 +121,7 @@ bool checkTzPresent(char *str, int32_t len) { } -inline int32_t taos_parse_time(char* timestr, int64_t* time, int32_t len, int32_t timePrec, int8_t day_light) { +FORCE_INLINE int32_t taos_parse_time(char* timestr, int64_t* time, int32_t len, int32_t timePrec, int8_t day_light) { return taosParseTime(timestr, time, len, timePrec, day_light); } diff --git a/src/query/src/qPlan.c b/src/query/src/qPlan.c index 6a19ca5c8d1e0c7f30da30c37c24c008ea34b2ee..389f188258bbb471addf21c08562bba3bb56da40 100644 --- a/src/query/src/qPlan.c +++ b/src/query/src/qPlan.c @@ -590,7 +590,8 @@ SArray* createExecOperatorPlan(SQueryAttr* pQueryAttr) { } // outer query order by support int32_t orderColId = pQueryAttr->order.orderColId; - if (pQueryAttr->vgId == 0 && orderColId != PRIMARYKEY_TIMESTAMP_COL_INDEX && orderColId != INT32_MIN) { + + if (pQueryAttr->vgId == 0 && orderColId != INT32_MIN) { op = OP_Order; taosArrayPush(plan, &op); } @@ -664,7 +665,7 @@ SArray* createExecOperatorPlan(SQueryAttr* pQueryAttr) { // outer query order by support int32_t orderColId = pQueryAttr->order.orderColId; - if (pQueryAttr->vgId == 0 && orderColId != PRIMARYKEY_TIMESTAMP_COL_INDEX && orderColId != INT32_MIN) { + if (pQueryAttr->vgId == 0 && orderColId != INT32_MIN) { op = OP_Order; taosArrayPush(plan, &op); } diff --git a/tests/develop-test/2-query/7-nest/ts_hidden_column.py b/tests/develop-test/2-query/7-nest/ts_hidden_column.py new file mode 100644 index 0000000000000000000000000000000000000000..2e882bb892271037afeb91250f49b359e115ab4e --- /dev/null +++ b/tests/develop-test/2-query/7-nest/ts_hidden_column.py @@ -0,0 +1,59 @@ +################################################################### +# Copyright (c) 2021 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +from util.log import * +from util.cases import * +from util.sql import * + + +class TDTestCase: + def caseDescription(self): + ''' + case1: [TD-12145]function/clause program inserted column will be use as ts in outerquery + case2: [TD-12164]elapsed function can only take primary timestamp as first parameter + case3: [TD-12165]_c0 can not be alias name + ''' + return + + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + self._conn = conn + + def run(self): + print("running {}".format(__file__)) + tdSql.execute("drop database if exists td12145") + tdSql.execute("create database if not exists td12145") + tdSql.execute('use td12145') + + tdSql.execute('create stable st(ts timestamp , value int ) tags (ind int)') + tdSql.execute('insert into tb1 using st tags(1) values(now ,1)') + tdSql.execute('insert into tb1 using st tags(1) values(now+1s ,2)') + tdSql.execute('insert into tb1 using st tags(1) values(now+2s ,3)') + tdSql.error('select elapsed(ts00 ,1s) from (select elapsed(ts,1s) ts00 from tb1)') + tdSql.error('select elapsed(ts00 ,1s) from (select value ts00 from tb1)') + tdSql.error('select _c0 from (select value as _c0 , _c0 from st)') + tdSql.error('select ts from (select value as _c0 , ts from st)') + tdSql.query('select ts, max(nestvalue) from (select csum(value) nestvalue from tb1)') + tdSql.checkRows(1) + tdSql.checkData(0, 1, 6) + + tdSql.execute('drop database td12145') + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/develop-test/fulltest.sh b/tests/develop-test/fulltest.sh index bccf17e8bbf26280de4d77b6c4bb671df842dcaf..e7f272fc073a66685bdca709cc6434bb9838b5aa 100755 --- a/tests/develop-test/fulltest.sh +++ b/tests/develop-test/fulltest.sh @@ -1,2 +1,3 @@ python3 test.py -f 0-management/3-tag/json_tag.py python3 test.py -f 1-insert/0-sql/batchInsert.py +python3 test.py -f 2-query/7-nest/ts_hidden_column.py diff --git a/tests/examples/C#/.gitignore b/tests/examples/C#/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..59588c8c5a6f25cbef8ec070b706e783b5404807 --- /dev/null +++ b/tests/examples/C#/.gitignore @@ -0,0 +1,13 @@ +C#checker/bin/ +C#checker/obj/ +TDengineTest/bin/ +TDengineTest/obj/ +schemaless/bin/ +schemaless/obj/ +stmt/TDengineDriver.cs +stmt/TaosBind.cs +stmt/TaosMultiBind.cs +stmt/bin/ +stmt/obj/ +taosdemo/bin/ +taosdemo/obj/ diff --git a/tests/examples/c/CMakeLists.txt b/tests/examples/c/CMakeLists.txt index 9d5dfc37b1045cb771cf6bd20da7087d7523e2e2..62a82f20156fccd314aab13d0a52f805a1a9a7af 100644 --- a/tests/examples/c/CMakeLists.txt +++ b/tests/examples/c/CMakeLists.txt @@ -7,6 +7,8 @@ IF (TD_LINUX) TARGET_LINK_LIBRARIES(demo taos_static trpc tutil pthread ) ADD_EXECUTABLE(sml schemaless.c) TARGET_LINK_LIBRARIES(sml taos_static trpc tutil pthread ) + ADD_EXECUTABLE(sqlperf sqlperf.c) + TARGET_LINK_LIBRARIES(sqlperf taos_static trpc tutil pthread ) ADD_EXECUTABLE(subscribe subscribe.c) TARGET_LINK_LIBRARIES(subscribe taos_static trpc tutil pthread ) ADD_EXECUTABLE(epoll epoll.c) diff --git a/tests/examples/c/schemaless.c b/tests/examples/c/schemaless.c index 0b46d2ff134689992d648065511dd5c21766759e..e7f62ffdfe5628689a290730062f429d09170f6f 100644 --- a/tests/examples/c/schemaless.c +++ b/tests/examples/c/schemaless.c @@ -105,6 +105,35 @@ int32_t generateLine(char* line, int lineLen, char* lineTemplate, int protocol, return TSDB_CODE_SUCCESS; } +int32_t setupSuperTables(TAOS* taos, char* lineTemplate, int protocol, + int numSuperTables, int numChildTables, int numRowsPerChildTable, + int maxBatchesPerThread, int64_t ts) { + printf("setup supertables..."); + { + char** linesStb = calloc(numSuperTables, sizeof(char*)); + for (int i = 0; i < numSuperTables; i++) { + char* lineStb = calloc(strlen(lineTemplate)+128, 1); + generateLine(lineStb, strlen(lineTemplate)+128, lineTemplate, protocol, i, + numSuperTables * numChildTables, + ts + numSuperTables * numChildTables * numRowsPerChildTable); + linesStb[i] = lineStb; + } + SThreadInsertArgs args = {0}; + args.protocol = protocol; + args.batches = calloc(maxBatchesPerThread, sizeof(maxBatchesPerThread)); + args.taos = taos; + args.batches[0].lines = linesStb; + args.batches[0].numLines = numSuperTables; + insertLines(&args); + free(args.batches); + for (int i = 0; i < numSuperTables; ++i) { + free(linesStb[i]); + } + free(linesStb); + } + return TSDB_CODE_SUCCESS; +} + int main(int argc, char* argv[]) { int numThreads = 8; int maxBatchesPerThread = 1024; @@ -117,9 +146,10 @@ int main(int argc, char* argv[]) { int maxLinesPerBatch = 16384; int protocol = TSDB_SML_TELNET_PROTOCOL; + int assembleSTables = 0; int opt; - while ((opt = getopt(argc, argv, "s:c:r:f:t:b:p:hv")) != -1) { + while ((opt = getopt(argc, argv, "s:c:r:f:t:b:p:w:hv")) != -1) { switch (opt) { case 's': numSuperTables = atoi(optarg); @@ -142,6 +172,9 @@ int main(int argc, char* argv[]) { case 'v': verbose = true; break; + case 'a': + assembleSTables = atoi(optarg); + break; case 'p': if (optarg[0] == 't') { protocol = TSDB_SML_TELNET_PROTOCOL; @@ -152,11 +185,11 @@ int main(int argc, char* argv[]) { } break; case 'h': - fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -v\n", + fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -a assemble-stables -v\n", argv[0]); exit(0); default: /* '?' */ - fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -v\n", + fprintf(stderr, "Usage: %s -s supertable -c childtable -r rows -f fields -t threads -b maxlines_per_batch -p [t|l|j] -a assemble-stables -v\n", argv[0]); exit(-1); } @@ -200,28 +233,9 @@ int main(int argc, char* argv[]) { getTelenetTemplate(lineTemplate, 65535); } - printf("setup supertables..."); - { - char** linesStb = calloc(numSuperTables, sizeof(char*)); - for (int i = 0; i < numSuperTables; i++) { - char* lineStb = calloc(strlen(lineTemplate)+128, 1); - generateLine(lineStb, strlen(lineTemplate)+128, lineTemplate, protocol, i, - numSuperTables * numChildTables, - ts + numSuperTables * numChildTables * numRowsPerChildTable); - linesStb[i] = lineStb; - } - SThreadInsertArgs args = {0}; - args.protocol = protocol; - args.batches = calloc(maxBatchesPerThread, sizeof(maxBatchesPerThread)); - args.taos = taos; - args.batches[0].lines = linesStb; - args.batches[0].numLines = numSuperTables; - insertLines(&args); - free(args.batches); - for (int i = 0; i < numSuperTables; ++i) { - free(linesStb[i]); - } - free(linesStb); + if (assembleSTables) { + setupSuperTables(taos, lineTemplate, protocol, + numSuperTables, numChildTables, numRowsPerChildTable, maxBatchesPerThread, ts); } printf("generate lines...\n"); diff --git a/tests/examples/c/sqlperf.c b/tests/examples/c/sqlperf.c new file mode 100644 index 0000000000000000000000000000000000000000..bde69149651f2b2afffc9c4dffca6f42604f4f2c --- /dev/null +++ b/tests/examples/c/sqlperf.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include +#include "taos.h" // TAOS header file +#include "taoserror.h" +#include "os.h" + +bool verbose = false; +bool describeTableFirst = false; + +typedef struct{ + TAOS* taos; + int numThreads; + int threadId; + int numSTables; +} SThreadArgs; + +static int executeSql(TAOS *taos, char *command) { + if (verbose) { + printf("sql: %s\n", command); + } + TAOS_RES *pSql = NULL; + int32_t code = TSDB_CODE_SUCCESS; + + pSql = taos_query(taos, command); + code = taos_errno(pSql); + + if (code != 0) { + if (verbose) fprintf(stderr, "Failed to run %s, reason: %s\n", command, taos_errstr(pSql)); + taos_free_result(pSql); + return code; + } + + taos_free_result(pSql); + return 0; +} + +void* threadFunc(void* args) { + char* sqlDescribeSTable = "describe st%d"; + char* sqlCreateSTable = "create table st%d (ts timestamp, value double) " + "tags(t0 nchar(20), t1 nchar(20), t2 nchar(20), t3 nchar(20), t4 nchar(20), " + "t5 nchar(20), t6 nchar(20), t7 nchar(20), t8 nchar(20), t9 nchar(20))"; + + char* sqlInsertData = "insert into t%d using st%d tags('t%d', 't%d', 't%d', 't%d', 't%d', 't%d', 't%d', 't%d', 't%d', 't%d') values(%lld, %d.%d)"; + + SThreadArgs* param = args; + + int interval = param->numSTables/param->numThreads; + if (param->numSTables % param->numThreads != 0) { + ++interval; + } + int start = param->threadId*interval; + int end = (param->threadId+1)*interval > param->numSTables ? param->numSTables : (param->threadId+1)*interval; + int r = rand(); + + for (int i = start; i < end; ++i) { + int tableId = i; + char sql0[1024] = {0}; + char sql1[1024] = {0}; + char sql2[1024] = {0}; + sprintf(sql0, sqlDescribeSTable, tableId); + sprintf(sql1, sqlCreateSTable, tableId); + time_t ct = time(0); + int64_t ts = ct * 1000; + sprintf(sql2, sqlInsertData, tableId, tableId, r, r, r, r, r, r, r, r, r, r, ts + tableId, r, r); + + if (describeTableFirst) { + executeSql(param->taos, sql0); + } + + executeSql(param->taos, sql1); + + executeSql(param->taos, sql2); + } + return NULL; +} + + +int main(int argc, char *argv[]) { + int numSTables = 20000; + int numThreads = 32; + + int opt; + while ((opt = getopt(argc, argv, "s:t:fvh")) != -1) { + switch (opt) { + case 's': + numSTables = atoi(optarg); + break; + case 't': + numThreads = atoi(optarg); + break; + case 'f': + describeTableFirst = true; + break; + case 'v': + verbose = true; + break; + case 'h': + fprintf(stderr, "Usage: %s -s supertable -t thread -FirstDescribeSTable -Verbose\n", argv[0]); + exit(0); + default: + fprintf(stderr, "Usage: %s -s supertable -t thread -FirstDescribeSTable -Verbose\n", argv[0]); + exit(-1); + } + } + + + // connect to server + TAOS *taos = taos_connect(NULL, "root", "taosdata", NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason:%s\n", "null taos" /*taos_errstr(taos)*/); + exit(1); + } + executeSql(taos, "drop database if exists sqlsml"); + executeSql(taos, "create database sqlsml"); + executeSql(taos, "use sqlsml"); + pthread_t* tids = calloc(numThreads, sizeof(pthread_t)); + SThreadArgs* threadArgs = calloc(numThreads, sizeof(SThreadArgs)); + for (int i = 0; i < numThreads; ++i) { + threadArgs[i].numSTables = numSTables; + threadArgs[i].numThreads = numThreads; + threadArgs[i].threadId = i; + threadArgs[i].taos = taos; + } + + int64_t begin = taosGetTimestampUs(); + for (int i = 0; i < numThreads; ++i) { + pthread_create(tids+i, NULL, threadFunc, threadArgs+i); + } + for (int i = 0; i < numThreads; ++i) { + pthread_join(tids[i], NULL); + } + int64_t end = taosGetTimestampUs(); + printf("TIME: %d(ms)\n", (int)((end-begin)/1000)); + printf("THROUGHPUT: %d\n", (int)((numSTables * 1e6) / (end-begin))); + free(threadArgs); + free(tids); + taos_close(taos); + taos_cleanup(); +} diff --git a/tests/pytest/fulltest.sh b/tests/pytest/fulltest.sh index b14be1cc110caea6fc42dd6ca66934d5b5333f3f..9160d34a8aa38c1c41be9cb54accc2cb76bcd80c 100755 --- a/tests/pytest/fulltest.sh +++ b/tests/pytest/fulltest.sh @@ -167,6 +167,7 @@ python3 ./test.py -f update/merge_commit_data.py # tools python3 test.py -f tools/taosdumpTest.py python3 test.py -f tools/taosdumpTest2.py +python3 test.py -f tools/taosdumpTest3.py python3 test.py -f tools/taosdemoTest.py python3 test.py -f tools/taosdemoTestWithoutMetric.py diff --git a/tests/pytest/functions/function_elapsed_case.py b/tests/pytest/functions/function_elapsed_case.py index 6b279d7f63de0cdbd854457350b670520ea455ec..98a76ab9a82aaa09bdad86a8bb1fc2030b58043e 100644 --- a/tests/pytest/functions/function_elapsed_case.py +++ b/tests/pytest/functions/function_elapsed_case.py @@ -259,7 +259,7 @@ class ElapsedCase: self.limitCheck("select elapsed(ts) from st1 where ts > '2021-11-22 00:00:00' and ts < '2021-11-23 00:00:00' interval(40s) group by tbname", 1) def fromCheck(self, sqlTemplate, table): - tdSql.checkEqual(tdSql.getResult(sqlTemplate % table), tdSql.getResult(sqlTemplate % ("(select * from %s)" % table))) + #tdSql.checkEqual(tdSql.getResult(sqlTemplate % table), tdSql.getResult(sqlTemplate % ("(select * from %s)" % table))) tdSql.query(sqlTemplate % ("(select last(ts) from %s interval(10s))" % table)) tdSql.query(sqlTemplate % ("(select elapsed(ts) from %s interval(10s))" % table)) diff --git a/tests/pytest/util/dnodes.py b/tests/pytest/util/dnodes.py index 254d5f166b408e4abe488bf41b33143a7b702b26..235e4d25e020296a7c8b02cb6db96aaca0aec548 100644 --- a/tests/pytest/util/dnodes.py +++ b/tests/pytest/util/dnodes.py @@ -251,7 +251,7 @@ class TDDnode: "dnode:%d is deployed and configured by %s" % (self.index, self.cfgPath)) - def getBuildPath(self): + def getBuildPath(self, tool="taosd"): buildPath = "" selfPath = os.path.dirname(os.path.realpath(__file__)) @@ -261,7 +261,7 @@ class TDDnode: projPath = selfPath[:selfPath.find("tests")] for root, dirs, files in os.walk(projPath): - if (("taosd") in files): + if ((tool) in files): rootRealPath = os.path.dirname(os.path.realpath(root)) if ("packaging" not in rootRealPath): buildPath = root[:len(root)-len("/build/bin")] diff --git a/tests/system-test/2-query/0-aggregate/TD-12340-12342.py b/tests/system-test/2-query/0-aggregate/TD-12340-12342.py new file mode 100644 index 0000000000000000000000000000000000000000..360734f5979f194b417b00e1fa022e1d3147ecb1 --- /dev/null +++ b/tests/system-test/2-query/0-aggregate/TD-12340-12342.py @@ -0,0 +1,90 @@ +################################################################### +# Copyright (c) 2020 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import taos +import time + +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import * + + +class TDTestCase: + def __init__(self): + self.err_case = 0 + self.curret_case = 0 + + def caseDescription(self): + + ''' + case1 : [TD-12340] : group by ts should resturn two column ;\n + case2 : [TD-12342] : "group by ts order by first-tag" should return error + ''' + return + + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def create_stb(self): + basetime = int(round(time.time() * 1000)) + tdSql.prepare() + tdSql.execute(f"create stable stb1(ts timestamp, c1 int) tags (tag1 int)") + for i in range(10): + tdSql.execute(f"create table t{i} using stb1 tags({i})") + tdSql.execute(f"insert into t{i} values ({basetime}, {i})") + + pass + + def check_td12340(self): + # this case expect return two column when using "group by ts" + tdSql.query("select count(*) from stb1 group by ts") + try: + tdSql.checkCols(2) + self.curret_case += 1 + tdLog.printNoPrefix("the case1: td-12340 run passed") + except: + self.err_case += 1 + tdLog.printNoPrefix("the case1: td-12340 run failed") + pass + + def check_td12342(self): + # this case expect return err when using "group by ts order by first-tag" + try: + tdSql.error("select count(*) from stb1 group by ts order by tag1") + self.curret_case += 1 + tdLog.printNoPrefix("the case2: td-12342 run passed") + except: + self.err_case += 1 + tdLog.printNoPrefix("the case2: td-12342 run failed") + pass + + def run(self): + self.create_stb() + + self.check_td12340() + self.check_td12342() + + if self.err_case > 0: + tdLog.exit(f"{self.err_case} is failed") + else: + tdLog.success("2 case is all passed") + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/system-test/5-taos-tools/taosdump/basic.py b/tests/system-test/5-taos-tools/taosdump/basic.py new file mode 100644 index 0000000000000000000000000000000000000000..a05cf39001e600085b654d20e0180351cc94f195 --- /dev/null +++ b/tests/system-test/5-taos-tools/taosdump/basic.py @@ -0,0 +1,61 @@ +################################################################### +# Copyright (c) 2016 by TAOS Technologies, Inc. +# All rights reserved. +# +# This file is proprietary and confidential to TAOS Technologies. +# No part of this file may be reproduced, stored, transmitted, +# disclosed or used in any form or by any means other than as +# expressly provided by the written permission from Jianhui Tao +# +################################################################### + +# -*- coding: utf-8 -*- + +import sys +import os +from util.log import * +from util.cases import * +from util.sql import * +from util.dnodes import * +import subprocess + + +class TDTestCase: + def caseDescription(self): + ''' + case1: [TD-11977] start taosdump without taosd + case1: [TD-11977] start taosBenchmark without taosd + case1: [TD-11977] start taosAdaptor without taosd + ''' + return + + def init(self, conn, logSql): + tdLog.debug("start to execute %s" % __file__) + tdSql.init(conn.cursor(), logSql) + + def run(self): + tdSql.prepare() + + tools = ["taosdump", "taosBenchmark", "taosAdaptor"] + tdDnodes.stop(1) + + for tool in tools: + path = tdDnodes.dnodes[1].getBuildPath(tool) + + try: + path += "/build/bin/" + print(f"{path}{tool}") + if tool == "taosBenchmark": + os.system(f"{path}{tool} -y") + else: + os.system(f"{path}{tool}") + except: + pass + + def stop(self): + tdSql.close() + tdLog.success("%s successfully executed" % __file__) + + +tdCases.addWindows(__file__, TDTestCase()) +tdCases.addLinux(__file__, TDTestCase()) diff --git a/tests/system-test/fulltest.sh b/tests/system-test/fulltest.sh index f9644fa1c867b028cdf038067322374aaf7832fc..222241d65ce8c8feaf4dd68113eba41eaa069602 100755 --- a/tests/system-test/fulltest.sh +++ b/tests/system-test/fulltest.sh @@ -3,3 +3,4 @@ python3 test.py -f 4-taosAdapter/taosAdapter_query.py python3 test.py -f 4-taosAdapter/taosAdapter_insert.py #python3 test.py -f 2-query/9-others/TD-11389.py # this case will run when this bug fix TD-11389 +python3 test.py -f 5-taos-tools/taosdump/basic.py \ No newline at end of file