提交 d0a77619 编写于 作者: sangshuduo's avatar sangshuduo

Merge branch 'develop' into hotfix/sangshuduo/TD-2984-combine-taosdemo-and-taosdemox

...@@ -43,7 +43,7 @@ CREATE STABLE meters (ts timestamp, current float, voltage int, phase float) TAG ...@@ -43,7 +43,7 @@ CREATE STABLE meters (ts timestamp, current float, voltage int, phase float) TAG
## <a class="anchor" id="create-table"></a>创建表 ## <a class="anchor" id="create-table"></a>创建表
TDengine对每个数据采集点需要独立建表。与标准的关系型数据一样,一张表有表名,Schema,但除此之外,还可以带有一到多个标签。创建时,需要使用超级表做模板,同时指定标签的具体值。以表一中的智能电表为例,可以使用如下的SQL命令建表: TDengine对每个数据采集点需要独立建表。与标准的关系型数据一样,一张表有表名,Schema,但除此之外,还可以带有一到多个标签。创建时,需要使用超级表做模板,同时指定标签的具体值。以表一中的智能电表为例,可以使用如下的SQL命令建表:
```cmd ```mysql
CREATE TABLE d1001 USING meters TAGS ("Beijing.Chaoyang", 2); CREATE TABLE d1001 USING meters TAGS ("Beijing.Chaoyang", 2);
``` ```
其中d1001是表名,meters是超级表的表名,后面紧跟标签Location的具体标签值”Beijing.Chaoyang",标签groupId的具体标签值2。虽然在创建表时,需要指定标签值,但可以事后修改。详细细则请见 [TAOS SQL 的表管理](https://www.taosdata.com/cn/documentation/taos-sql#table) 章节。 其中d1001是表名,meters是超级表的表名,后面紧跟标签Location的具体标签值”Beijing.Chaoyang",标签groupId的具体标签值2。虽然在创建表时,需要指定标签值,但可以事后修改。详细细则请见 [TAOS SQL 的表管理](https://www.taosdata.com/cn/documentation/taos-sql#table) 章节。
...@@ -54,10 +54,12 @@ TDengine建议将数据采集点的全局唯一ID作为表名(比如设备序列 ...@@ -54,10 +54,12 @@ TDengine建议将数据采集点的全局唯一ID作为表名(比如设备序列
**自动建表**:在某些特殊场景中,用户在写数据时并不确定某个数据采集点的表是否存在,此时可在写入数据时使用自动建表语法来创建不存在的表,若该表已存在则不会建立新表。比如: **自动建表**:在某些特殊场景中,用户在写数据时并不确定某个数据采集点的表是否存在,此时可在写入数据时使用自动建表语法来创建不存在的表,若该表已存在则不会建立新表。比如:
```cmd ```mysql
INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32); INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
``` ```
上述SQL语句将记录(now, 10.2, 219, 0.32) 插入进表d1001。如果表d1001还未创建,则使用超级表meters做模板自动创建,同时打上标签值“Beijing.Chaoyang", 2。 上述SQL语句将记录 (now, 10.2, 219, 0.32) 插入表d1001。如果表d1001还未创建,则使用超级表meters做模板自动创建,同时打上标签值“Beijing.Chaoyang", 2。
关于自动建表的详细语法请参见 [插入记录时自动建表](https://www.taosdata.com/cn/documentation/taos-sql#auto_create_table) 章节。
## 多列模型 vs 单列模型 ## 多列模型 vs 单列模型
......
...@@ -152,6 +152,14 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic ...@@ -152,6 +152,14 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
``` ```
以指定的超级表为模板,指定 tags 的值来创建数据表。 以指定的超级表为模板,指定 tags 的值来创建数据表。
- **以超级表为模板创建数据表,并指定具体的 tags 列**
```mysql
CREATE TABLE [IF NOT EXISTS] tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...);
```
以指定的超级表为模板,指定一部分 tags 列的值来创建数据表。(没被指定的 tags 列会设为空值。)
说明:从 2.0.17 版本开始支持这种方式。在之前的版本中,不允许指定 tags 列,而必须显式给出所有 tags 列的取值。
- **批量创建数据表** - **批量创建数据表**
```mysql ```mysql
...@@ -306,7 +314,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic ...@@ -306,7 +314,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
- **插入一条记录,数据对应到指定的列** - **插入一条记录,数据对应到指定的列**
```mysql ```mysql
INSERT INTO tb_name (field1_name, ...) VALUES (field1_value, ...) INSERT INTO tb_name (field1_name, ...) VALUES (field1_value1, ...);
``` ```
向表tb_name中插入一条记录,数据对应到指定的列。SQL语句中没有出现的列,数据库将自动填充为NULL。主键(时间戳)不能为NULL。 向表tb_name中插入一条记录,数据对应到指定的列。SQL语句中没有出现的列,数据库将自动填充为NULL。主键(时间戳)不能为NULL。
...@@ -340,25 +348,19 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic ...@@ -340,25 +348,19 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
1) 如果时间戳为0,系统将自动使用服务器当前时间作为该记录的时间戳; 1) 如果时间戳为0,系统将自动使用服务器当前时间作为该记录的时间戳;
2) 允许插入的最老记录的时间戳,是相对于当前服务器时间,减去配置的keep值(数据保留的天数),允许插入的最新记录的时间戳,是相对于当前服务器时间,加上配置的days值(数据文件存储数据的时间跨度,单位为天)。keep和days都是可以在创建数据库时指定的,缺省值分别是3650天和10天。 2) 允许插入的最老记录的时间戳,是相对于当前服务器时间,减去配置的keep值(数据保留的天数),允许插入的最新记录的时间戳,是相对于当前服务器时间,加上配置的days值(数据文件存储数据的时间跨度,单位为天)。keep和days都是可以在创建数据库时指定的,缺省值分别是3650天和10天。
**历史记录写入**:可使用IMPORT或者INSERT命令,IMPORT的语法,功能与INSERT完全一样。 - <a class="anchor" id="auto_create_table"></a>**插入记录时自动建表**
```mysql
## <a class="anchor" id="select"></a>数据查询 INSERT INTO tb_name USING stb_name TAGS (tag_value1, ...) VALUES (field_value1, ...);
```
如果用户在写数据时并不确定某个表是否存在,此时可以在写入数据时使用自动建表语法来创建不存在的表,若该表已存在则不会建立新表。自动建表时,要求必须以超级表为模板,并写明数据表的 tags 取值。
### 查询语法: - **插入记录时自动建表,并指定具体的 tags 列**
```mysql
INSERT INTO tb_name USING stb_name (tag_name1, ...) TAGS (tag_value1, ...) VALUES (field_value1, ...);
```
在自动建表时,可以只是指定部分 tags 列的取值,未被指定的 tags 列将取为空值。
```mysql **历史记录写入**:可使用IMPORT或者INSERT命令,IMPORT的语法,功能与INSERT完全一样。
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file]
```
说明:针对 insert 类型的 SQL 语句,我们采用的流式解析策略,在发现后面的错误之前,前面正确的部分SQL仍会执行。下面的sql中,insert语句是无效的,但是d1001仍会被创建。 说明:针对 insert 类型的 SQL 语句,我们采用的流式解析策略,在发现后面的错误之前,前面正确的部分SQL仍会执行。下面的sql中,insert语句是无效的,但是d1001仍会被创建。
...@@ -386,6 +388,24 @@ taos> SHOW TABLES; ...@@ -386,6 +388,24 @@ taos> SHOW TABLES;
Query OK, 1 row(s) in set (0.001091s) Query OK, 1 row(s) in set (0.001091s)
``` ```
## <a class="anchor" id="select"></a>数据查询
### 查询语法:
```mysql
SELECT select_expr [, select_expr ...]
FROM {tb_name_list}
[WHERE where_condition]
[INTERVAL (interval_val [, interval_offset])]
[FILL fill_val]
[SLIDING fill_val]
[GROUP BY col_list]
[ORDER BY col_list { DESC | ASC }]
[SLIMIT limit_val [, SOFFSET offset_val]]
[LIMIT limit_val [, OFFSET offset_val]]
[>> export_file];
```
#### SELECT子句 #### SELECT子句
一个选择子句可以是联合查询(UNION)和另一个查询的子查询(SUBQUERY)。 一个选择子句可以是联合查询(UNION)和另一个查询的子查询(SUBQUERY)。
......
...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python( ...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python( ...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False): ...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False):
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python( ...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
......
...@@ -19,10 +19,10 @@ class FieldType(object): ...@@ -19,10 +19,10 @@ class FieldType(object):
C_BINARY = 8 C_BINARY = 8
C_TIMESTAMP = 9 C_TIMESTAMP = 9
C_NCHAR = 10 C_NCHAR = 10
C_TINYINT_UNSIGNED = 12 C_TINYINT_UNSIGNED = 11
C_SMALLINT_UNSIGNED = 13 C_SMALLINT_UNSIGNED = 12
C_INT_UNSIGNED = 14 C_INT_UNSIGNED = 13
C_BIGINT_UNSIGNED = 15 C_BIGINT_UNSIGNED = 14
# NULL value definition # NULL value definition
# NOTE: These values should change according to C definition in tsdb.h # NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL = 0x02 C_BOOL_NULL = 0x02
......
...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python( ...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python( ...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False): ...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False):
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python( ...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
......
...@@ -19,10 +19,10 @@ class FieldType(object): ...@@ -19,10 +19,10 @@ class FieldType(object):
C_BINARY = 8 C_BINARY = 8
C_TIMESTAMP = 9 C_TIMESTAMP = 9
C_NCHAR = 10 C_NCHAR = 10
C_TINYINT_UNSIGNED = 12 C_TINYINT_UNSIGNED = 11
C_SMALLINT_UNSIGNED = 13 C_SMALLINT_UNSIGNED = 12
C_INT_UNSIGNED = 14 C_INT_UNSIGNED = 13
C_BIGINT_UNSIGNED = 15 C_BIGINT_UNSIGNED = 14
# NULL value definition # NULL value definition
# NOTE: These values should change according to C definition in tsdb.h # NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL = 0x02 C_BOOL_NULL = 0x02
......
...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python( ...@@ -67,13 +67,13 @@ def _crow_tinyint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_byte))[ ctypes.c_ubyte))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python( ...@@ -102,13 +102,13 @@ def _crow_smallint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_short))[ ctypes.c_ushort))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False): ...@@ -130,13 +130,13 @@ def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False):
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_int))[ ctypes.c_uint))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python( ...@@ -162,13 +162,13 @@ def _crow_bigint_unsigned_to_python(
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
else: else:
return [ return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast( None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER( data, ctypes.POINTER(
ctypes.c_long))[ ctypes.c_ulong))[
:abs(num_of_rows)]] :abs(num_of_rows)]]
......
...@@ -19,10 +19,10 @@ class FieldType(object): ...@@ -19,10 +19,10 @@ class FieldType(object):
C_BINARY = 8 C_BINARY = 8
C_TIMESTAMP = 9 C_TIMESTAMP = 9
C_NCHAR = 10 C_NCHAR = 10
C_TINYINT_UNSIGNED = 12 C_TINYINT_UNSIGNED = 11
C_SMALLINT_UNSIGNED = 13 C_SMALLINT_UNSIGNED = 12
C_INT_UNSIGNED = 14 C_INT_UNSIGNED = 13
C_BIGINT_UNSIGNED = 15 C_BIGINT_UNSIGNED = 14
# NULL value definition # NULL value definition
# NOTE: These values should change according to C definition in tsdb.h # NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL = 0x02 C_BOOL_NULL = 0x02
......
...@@ -8,6 +8,7 @@ paramstyle = 'pyformat' ...@@ -8,6 +8,7 @@ paramstyle = 'pyformat'
__all__ = ['connection', 'cursor'] __all__ = ['connection', 'cursor']
def connect(*args, **kwargs): def connect(*args, **kwargs):
""" Function to return a TDengine connector object """ Function to return a TDengine connector object
......
...@@ -4,11 +4,14 @@ from .error import * ...@@ -4,11 +4,14 @@ from .error import *
import math import math
import datetime import datetime
def _convert_millisecond_to_datetime(milli): def _convert_millisecond_to_datetime(milli):
return datetime.datetime.fromtimestamp(milli/1000.0) return datetime.datetime.fromtimestamp(milli / 1000.0)
def _convert_microsecond_to_datetime(micro): def _convert_microsecond_to_datetime(micro):
return datetime.datetime.fromtimestamp(micro/1000000.0) return datetime.datetime.fromtimestamp(micro / 1000000.0)
def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bool row to python row """Function to convert C bool row to python row
...@@ -18,168 +21,309 @@ def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False): ...@@ -18,168 +21,309 @@ def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False):
_timestamp_converter = _convert_microsecond_to_datetime _timestamp_converter = _convert_microsecond_to_datetime
if num_of_rows > 0: if num_of_rows > 0:
return list(map(_timestamp_converter, ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)])) return list(map(_timestamp_converter, ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]))
else: else:
return list(map(_timestamp_converter, ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)])) return list(map(_timestamp_converter, ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]))
def _crow_bool_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_bool_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bool row to python row """Function to convert C bool row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_byte))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_bool))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_bool))[
:abs(num_of_rows)]]
def _crow_tinyint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_tinyint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C tinyint row to python row """Function to convert C tinyint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)]]
else:
return [None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)]]
def _crow_tinyint_unsigned_to_python(
data,
num_of_rows,
nbytes=None,
micro=False):
"""Function to convert C tinyint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ubyte))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ubyte))[
:abs(num_of_rows)]]
def _crow_smallint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_smallint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C smallint row to python row """Function to convert C smallint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_short))[:abs(num_of_rows)]] return [
None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_short))[
:abs(num_of_rows)]]
else:
return [
None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_short))[
:abs(num_of_rows)]]
def _crow_smallint_unsigned_to_python(
data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C smallint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ushort))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_short))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ushort))[
:abs(num_of_rows)]]
def _crow_int_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_int_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C int row to python row """Function to convert C int row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)]]
def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C int row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_uint))[
:abs(num_of_rows)]]
else:
return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_uint))[
:abs(num_of_rows)]]
def _crow_bigint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_bigint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bigint row to python row """Function to convert C bigint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]]
else:
return [None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]]
def _crow_bigint_unsigned_to_python(
data,
num_of_rows,
nbytes=None,
micro=False):
"""Function to convert C bigint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ulong))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ulong))[
:abs(num_of_rows)]]
def _crow_float_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_float_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C float row to python row """Function to convert C float row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)]]
else: else:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)]]
def _crow_double_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_double_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C double row to python row """Function to convert C double row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)]]
else: else:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)]]
def _crow_binary_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_binary_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C binary row to python row """Function to convert C binary row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode('utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]] return [None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode(
'utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]]
else: else:
return [ None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode('utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]] return [None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode(
'utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]]
def _crow_nchar_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_nchar_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C nchar row to python row """Function to convert C nchar row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res=[] res = []
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
if num_of_rows >= 0: if num_of_rows >= 0:
tmpstr = ctypes.c_char_p(data) tmpstr = ctypes.c_char_p(data)
res.append( tmpstr.value.decode() ) res.append(tmpstr.value.decode())
else: else:
res.append( (ctypes.cast(data+nbytes*i, ctypes.POINTER(ctypes.c_wchar * (nbytes//4))))[0].value ) res.append((ctypes.cast(data + nbytes * i,
ctypes.POINTER(ctypes.c_wchar * (nbytes // 4))))[0].value)
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
def _crow_binary_to_python_block(data, num_of_rows, nbytes=None, micro=False): def _crow_binary_to_python_block(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C binary row to python row """Function to convert C binary row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res=[] res = []
if num_of_rows > 0: if num_of_rows > 0:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
rbyte=ctypes.cast(data+nbytes*i,ctypes.POINTER(ctypes.c_short))[:1].pop() rbyte = ctypes.cast(
tmpstr = ctypes.c_char_p(data+nbytes*i+2) data + nbytes * i,
res.append( tmpstr.value.decode()[0:rbyte] ) ctypes.POINTER(
ctypes.c_short))[
:1].pop()
tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append(tmpstr.value.decode()[0:rbyte])
except ValueError: except ValueError:
res.append(None) res.append(None)
else: else:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
rbyte=ctypes.cast(data+nbytes*i,ctypes.POINTER(ctypes.c_short))[:1].pop() rbyte = ctypes.cast(
tmpstr = ctypes.c_char_p(data+nbytes*i+2) data + nbytes * i,
res.append( tmpstr.value.decode()[0:rbyte] ) ctypes.POINTER(
ctypes.c_short))[
:1].pop()
tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append(tmpstr.value.decode()[0:rbyte])
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
def _crow_nchar_to_python_block(data, num_of_rows, nbytes=None, micro=False): def _crow_nchar_to_python_block(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C nchar row to python row """Function to convert C nchar row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res=[] res = []
if num_of_rows >= 0: if num_of_rows >= 0:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
tmpstr = ctypes.c_char_p(data+nbytes*i+2) tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append( tmpstr.value.decode() ) res.append(tmpstr.value.decode())
except ValueError: except ValueError:
res.append(None) res.append(None)
else: else:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
res.append( (ctypes.cast(data+nbytes*i+2, ctypes.POINTER(ctypes.c_wchar * (nbytes//4))))[0].value ) res.append((ctypes.cast(data + nbytes * i + 2,
ctypes.POINTER(ctypes.c_wchar * (nbytes // 4))))[0].value)
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
_CONVERT_FUNC = { _CONVERT_FUNC = {
FieldType.C_BOOL: _crow_bool_to_python, FieldType.C_BOOL: _crow_bool_to_python,
FieldType.C_TINYINT : _crow_tinyint_to_python, FieldType.C_TINYINT: _crow_tinyint_to_python,
FieldType.C_SMALLINT : _crow_smallint_to_python, FieldType.C_SMALLINT: _crow_smallint_to_python,
FieldType.C_INT : _crow_int_to_python, FieldType.C_INT: _crow_int_to_python,
FieldType.C_BIGINT : _crow_bigint_to_python, FieldType.C_BIGINT: _crow_bigint_to_python,
FieldType.C_FLOAT : _crow_float_to_python, FieldType.C_FLOAT: _crow_float_to_python,
FieldType.C_DOUBLE : _crow_double_to_python, FieldType.C_DOUBLE: _crow_double_to_python,
FieldType.C_BINARY: _crow_binary_to_python, FieldType.C_BINARY: _crow_binary_to_python,
FieldType.C_TIMESTAMP : _crow_timestamp_to_python, FieldType.C_TIMESTAMP: _crow_timestamp_to_python,
FieldType.C_NCHAR : _crow_nchar_to_python FieldType.C_NCHAR: _crow_nchar_to_python,
FieldType.C_TINYINT_UNSIGNED: _crow_tinyint_unsigned_to_python,
FieldType.C_SMALLINT_UNSIGNED: _crow_smallint_unsigned_to_python,
FieldType.C_INT_UNSIGNED: _crow_int_unsigned_to_python,
FieldType.C_BIGINT_UNSIGNED: _crow_bigint_unsigned_to_python
} }
_CONVERT_FUNC_BLOCK = { _CONVERT_FUNC_BLOCK = {
FieldType.C_BOOL: _crow_bool_to_python, FieldType.C_BOOL: _crow_bool_to_python,
FieldType.C_TINYINT : _crow_tinyint_to_python, FieldType.C_TINYINT: _crow_tinyint_to_python,
FieldType.C_SMALLINT : _crow_smallint_to_python, FieldType.C_SMALLINT: _crow_smallint_to_python,
FieldType.C_INT : _crow_int_to_python, FieldType.C_INT: _crow_int_to_python,
FieldType.C_BIGINT : _crow_bigint_to_python, FieldType.C_BIGINT: _crow_bigint_to_python,
FieldType.C_FLOAT : _crow_float_to_python, FieldType.C_FLOAT: _crow_float_to_python,
FieldType.C_DOUBLE : _crow_double_to_python, FieldType.C_DOUBLE: _crow_double_to_python,
FieldType.C_BINARY: _crow_binary_to_python_block, FieldType.C_BINARY: _crow_binary_to_python_block,
FieldType.C_TIMESTAMP : _crow_timestamp_to_python, FieldType.C_TIMESTAMP: _crow_timestamp_to_python,
FieldType.C_NCHAR : _crow_nchar_to_python_block FieldType.C_NCHAR: _crow_nchar_to_python_block,
FieldType.C_TINYINT_UNSIGNED: _crow_tinyint_unsigned_to_python,
FieldType.C_SMALLINT_UNSIGNED: _crow_smallint_unsigned_to_python,
FieldType.C_INT_UNSIGNED: _crow_int_unsigned_to_python,
FieldType.C_BIGINT_UNSIGNED: _crow_bigint_unsigned_to_python
} }
# Corresponding TAOS_FIELD structure in C # Corresponding TAOS_FIELD structure in C
class TaosField(ctypes.Structure): class TaosField(ctypes.Structure):
_fields_ = [('name', ctypes.c_char * 65), _fields_ = [('name', ctypes.c_char * 65),
('type', ctypes.c_char), ('type', ctypes.c_char),
('bytes', ctypes.c_short)] ('bytes', ctypes.c_short)]
# C interface class # C interface class
class CTaosInterface(object): class CTaosInterface(object):
libtaos = ctypes.windll.LoadLibrary('taos') libtaos = ctypes.windll.LoadLibrary('taos')
...@@ -216,7 +360,7 @@ class CTaosInterface(object): ...@@ -216,7 +360,7 @@ class CTaosInterface(object):
except AttributeError: except AttributeError:
raise AttributeError("config is expected as a str") raise AttributeError("config is expected as a str")
if config != None: if config is not None:
CTaosInterface.libtaos.taos_options(3, self._config) CTaosInterface.libtaos.taos_options(3, self._config)
CTaosInterface.libtaos.taos_init() CTaosInterface.libtaos.taos_init()
...@@ -227,7 +371,13 @@ class CTaosInterface(object): ...@@ -227,7 +371,13 @@ class CTaosInterface(object):
""" """
return self._config return self._config
def connect(self, host=None, user="root", password="taosdata", db=None, port=0): def connect(
self,
host=None,
user="root",
password="taosdata",
db=None,
port=0):
''' '''
Function to connect to server Function to connect to server
...@@ -236,7 +386,7 @@ class CTaosInterface(object): ...@@ -236,7 +386,7 @@ class CTaosInterface(object):
# host # host
try: try:
_host = ctypes.c_char_p(host.encode( _host = ctypes.c_char_p(host.encode(
"utf-8")) if host != None else ctypes.c_char_p(None) "utf-8")) if host is not None else ctypes.c_char_p(None)
except AttributeError: except AttributeError:
raise AttributeError("host is expected as a str") raise AttributeError("host is expected as a str")
...@@ -255,7 +405,7 @@ class CTaosInterface(object): ...@@ -255,7 +405,7 @@ class CTaosInterface(object):
# db # db
try: try:
_db = ctypes.c_char_p( _db = ctypes.c_char_p(
db.encode("utf-8")) if db != None else ctypes.c_char_p(None) db.encode("utf-8")) if db is not None else ctypes.c_char_p(None)
except AttributeError: except AttributeError:
raise AttributeError("db is expected as a str") raise AttributeError("db is expected as a str")
...@@ -268,11 +418,11 @@ class CTaosInterface(object): ...@@ -268,11 +418,11 @@ class CTaosInterface(object):
connection = ctypes.c_void_p(CTaosInterface.libtaos.taos_connect( connection = ctypes.c_void_p(CTaosInterface.libtaos.taos_connect(
_host, _user, _password, _db, _port)) _host, _user, _password, _db, _port))
if connection.value == None: if connection.value is None:
print('connect to TDengine failed') print('connect to TDengine failed')
raise ConnectionError("connect to TDengine failed") raise ConnectionError("connect to TDengine failed")
# sys.exit(1) # sys.exit(1)
#else: # else:
# print('connect to TDengine success') # print('connect to TDengine success')
return connection return connection
...@@ -293,12 +443,13 @@ class CTaosInterface(object): ...@@ -293,12 +443,13 @@ class CTaosInterface(object):
@rtype: 0 on success and -1 on failure @rtype: 0 on success and -1 on failure
''' '''
try: try:
return CTaosInterface.libtaos.taos_query(connection, ctypes.c_char_p(sql.encode('utf-8'))) return CTaosInterface.libtaos.taos_query(
connection, ctypes.c_char_p(sql.encode('utf-8')))
except AttributeError: except AttributeError:
raise AttributeError("sql is expected as a string") raise AttributeError("sql is expected as a string")
# finally: # finally:
# CTaosInterface.libtaos.close(connection) # CTaosInterface.libtaos.close(connection)
@staticmethod @staticmethod
def affectedRows(result): def affectedRows(result):
"""The affected rows after runing query """The affected rows after runing query
...@@ -308,7 +459,7 @@ class CTaosInterface(object): ...@@ -308,7 +459,7 @@ class CTaosInterface(object):
@staticmethod @staticmethod
def subscribe(connection, restart, topic, sql, interval): def subscribe(connection, restart, topic, sql, interval):
"""Create a subscription """Create a subscription
@restart boolean, @restart boolean,
@sql string, sql statement for data query, must be a 'select' statement. @sql string, sql statement for data query, must be a 'select' statement.
@topic string, name of this subscription @topic string, name of this subscription
""" """
...@@ -360,35 +511,49 @@ class CTaosInterface(object): ...@@ -360,35 +511,49 @@ class CTaosInterface(object):
result, ctypes.byref(pblock)) result, ctypes.byref(pblock))
if num_of_rows == 0: if num_of_rows == 0:
return None, 0 return None, 0
isMicro = (CTaosInterface.libtaos.taos_result_precision(result) == FieldType.C_TIMESTAMP_MICRO) isMicro = (CTaosInterface.libtaos.taos_result_precision(
result) == FieldType.C_TIMESTAMP_MICRO)
blocks = [None] * len(fields) blocks = [None] * len(fields)
fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result) fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result)
fieldLen = [ele for ele in ctypes.cast(fieldL, ctypes.POINTER(ctypes.c_int))[:len(fields)]] fieldLen = [
ele for ele in ctypes.cast(
fieldL, ctypes.POINTER(
ctypes.c_int))[
:len(fields)]]
for i in range(len(fields)): for i in range(len(fields)):
data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i] data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i]
if fields[i]['type'] not in _CONVERT_FUNC_BLOCK: if fields[i]['type'] not in _CONVERT_FUNC_BLOCK:
raise DatabaseError("Invalid data type returned from database") raise DatabaseError("Invalid data type returned from database")
blocks[i] = _CONVERT_FUNC_BLOCK[fields[i]['type']](data, num_of_rows, fieldLen[i], isMicro) blocks[i] = _CONVERT_FUNC_BLOCK[fields[i]['type']](
data, num_of_rows, fieldLen[i], isMicro)
return blocks, abs(num_of_rows) return blocks, abs(num_of_rows)
@staticmethod @staticmethod
def fetchRow(result, fields): def fetchRow(result, fields):
pblock = ctypes.c_void_p(0) pblock = ctypes.c_void_p(0)
pblock = CTaosInterface.libtaos.taos_fetch_row(result) pblock = CTaosInterface.libtaos.taos_fetch_row(result)
if pblock : if pblock:
num_of_rows = 1 num_of_rows = 1
isMicro = (CTaosInterface.libtaos.taos_result_precision(result) == FieldType.C_TIMESTAMP_MICRO) isMicro = (CTaosInterface.libtaos.taos_result_precision(
result) == FieldType.C_TIMESTAMP_MICRO)
blocks = [None] * len(fields) blocks = [None] * len(fields)
fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result) fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result)
fieldLen = [ele for ele in ctypes.cast(fieldL, ctypes.POINTER(ctypes.c_int))[:len(fields)]] fieldLen = [
ele for ele in ctypes.cast(
fieldL, ctypes.POINTER(
ctypes.c_int))[
:len(fields)]]
for i in range(len(fields)): for i in range(len(fields)):
data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i] data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i]
if fields[i]['type'] not in _CONVERT_FUNC: if fields[i]['type'] not in _CONVERT_FUNC:
raise DatabaseError("Invalid data type returned from database") raise DatabaseError(
"Invalid data type returned from database")
if data is None: if data is None:
blocks[i] = [None] blocks[i] = [None]
else: else:
blocks[i] = _CONVERT_FUNC[fields[i]['type']](data, num_of_rows, fieldLen[i], isMicro) blocks[i] = _CONVERT_FUNC[fields[i]['type']](
data, num_of_rows, fieldLen[i], isMicro)
else: else:
return None, 0 return None, 0
return blocks, abs(num_of_rows) return blocks, abs(num_of_rows)
......
...@@ -2,9 +2,11 @@ from .cursor import TDengineCursor ...@@ -2,9 +2,11 @@ from .cursor import TDengineCursor
from .subscription import TDengineSubscription from .subscription import TDengineSubscription
from .cinterface import CTaosInterface from .cinterface import CTaosInterface
class TDengineConnection(object): class TDengineConnection(object):
""" TDengine connection object """ TDengine connection object
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._conn = None self._conn = None
self._host = None self._host = None
...@@ -30,7 +32,7 @@ class TDengineConnection(object): ...@@ -30,7 +32,7 @@ class TDengineConnection(object):
# password # password
if 'password' in kwargs: if 'password' in kwargs:
self._password = kwargs['password'] self._password = kwargs['password']
# database # database
if 'database' in kwargs: if 'database' in kwargs:
self._database = kwargs['database'] self._database = kwargs['database']
...@@ -44,7 +46,12 @@ class TDengineConnection(object): ...@@ -44,7 +46,12 @@ class TDengineConnection(object):
self._config = kwargs['config'] self._config = kwargs['config']
self._chandle = CTaosInterface(self._config) self._chandle = CTaosInterface(self._config)
self._conn = self._chandle.connect(self._host, self._user, self._password, self._database, self._port) self._conn = self._chandle.connect(
self._host,
self._user,
self._password,
self._database,
self._port)
def close(self): def close(self):
"""Close current connection. """Close current connection.
...@@ -56,7 +63,8 @@ class TDengineConnection(object): ...@@ -56,7 +63,8 @@ class TDengineConnection(object):
""" """
if self._conn is None: if self._conn is None:
return None return None
sub = CTaosInterface.subscribe(self._conn, restart, topic, sql, interval) sub = CTaosInterface.subscribe(
self._conn, restart, topic, sql, interval)
return TDengineSubscription(sub) return TDengineSubscription(sub)
def cursor(self): def cursor(self):
...@@ -81,7 +89,8 @@ class TDengineConnection(object): ...@@ -81,7 +89,8 @@ class TDengineConnection(object):
""" """
pass pass
if __name__ == "__main__": if __name__ == "__main__":
conn = TDengineConnection(host='192.168.1.107') conn = TDengineConnection(host='192.168.1.107')
conn.close() conn.close()
print("Hello world") print("Hello world")
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
from .dbapi import * from .dbapi import *
class FieldType(object): class FieldType(object):
"""TDengine Field Types """TDengine Field Types
""" """
...@@ -18,13 +19,21 @@ class FieldType(object): ...@@ -18,13 +19,21 @@ class FieldType(object):
C_BINARY = 8 C_BINARY = 8
C_TIMESTAMP = 9 C_TIMESTAMP = 9
C_NCHAR = 10 C_NCHAR = 10
C_TINYINT_UNSIGNED = 11
C_SMALLINT_UNSIGNED = 12
C_INT_UNSIGNED = 13
C_BIGINT_UNSIGNED = 14
# NULL value definition # NULL value definition
# NOTE: These values should change according to C definition in tsdb.h # NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL = 0x02 C_BOOL_NULL = 0x02
C_TINYINT_NULL = -128 C_TINYINT_NULL = -128
C_TINYINT_UNSIGNED_NULL = 255
C_SMALLINT_NULL = -32768 C_SMALLINT_NULL = -32768
C_SMALLINT_UNSIGNED_NULL = 65535
C_INT_NULL = -2147483648 C_INT_NULL = -2147483648
C_INT_UNSIGNED_NULL = 4294967295
C_BIGINT_NULL = -9223372036854775808 C_BIGINT_NULL = -9223372036854775808
C_BIGINT_UNSIGNED_NULL = 18446744073709551615
C_FLOAT_NULL = float('nan') C_FLOAT_NULL = float('nan')
C_DOUBLE_NULL = float('nan') C_DOUBLE_NULL = float('nan')
C_BINARY_NULL = bytearray([int('0xff', 16)]) C_BINARY_NULL = bytearray([int('0xff', 16)])
......
...@@ -5,6 +5,7 @@ import threading ...@@ -5,6 +5,7 @@ import threading
# querySeqNum = 0 # querySeqNum = 0
class TDengineCursor(object): class TDengineCursor(object):
"""Database cursor which is used to manage the context of a fetch operation. """Database cursor which is used to manage the context of a fetch operation.
...@@ -23,7 +24,7 @@ class TDengineCursor(object): ...@@ -23,7 +24,7 @@ class TDengineCursor(object):
if the cursor has not had an operation invoked via the .execute*() method yet. if the cursor has not had an operation invoked via the .execute*() method yet.
.rowcount:This read-only attribute specifies the number of rows that the last .rowcount:This read-only attribute specifies the number of rows that the last
.execute*() produced (for DQL statements like SELECT) or affected .execute*() produced (for DQL statements like SELECT) or affected
""" """
def __init__(self, connection=None): def __init__(self, connection=None):
...@@ -50,13 +51,14 @@ class TDengineCursor(object): ...@@ -50,13 +51,14 @@ class TDengineCursor(object):
raise OperationalError("Invalid use of fetch iterator") raise OperationalError("Invalid use of fetch iterator")
if self._block_rows <= self._block_iter: if self._block_rows <= self._block_iter:
block, self._block_rows = CTaosInterface.fetchRow(self._result, self._fields) block, self._block_rows = CTaosInterface.fetchRow(
self._result, self._fields)
if self._block_rows == 0: if self._block_rows == 0:
raise StopIteration raise StopIteration
self._block = list(map(tuple, zip(*block))) self._block = list(map(tuple, zip(*block)))
self._block_iter = 0 self._block_iter = 0
data = self._block[self._block_iter] data = self._block[self._block_iter]
self._block_iter += 1 self._block_iter += 1
return data return data
...@@ -91,7 +93,7 @@ class TDengineCursor(object): ...@@ -91,7 +93,7 @@ class TDengineCursor(object):
""" """
if self._connection is None: if self._connection is None:
return False return False
self._reset_result() self._reset_result()
self._connection = None self._connection = None
...@@ -106,19 +108,20 @@ class TDengineCursor(object): ...@@ -106,19 +108,20 @@ class TDengineCursor(object):
if not self._connection: if not self._connection:
# TODO : change the exception raised here # TODO : change the exception raised here
raise ProgrammingError("Cursor is not connected") raise ProgrammingError("Cursor is not connected")
self._reset_result() self._reset_result()
stmt = operation stmt = operation
if params is not None: if params is not None:
pass pass
self._result = CTaosInterface.query(self._connection._conn, stmt) self._result = CTaosInterface.query(self._connection._conn, stmt)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno == 0: if errno == 0:
if CTaosInterface.fieldsCount(self._result) == 0: if CTaosInterface.fieldsCount(self._result) == 0:
self._affected_rows += CTaosInterface.affectedRows(self._result) self._affected_rows += CTaosInterface.affectedRows(
return CTaosInterface.affectedRows(self._result ) self._result)
return CTaosInterface.affectedRows(self._result)
else: else:
self._fields = CTaosInterface.useResult(self._result) self._fields = CTaosInterface.useResult(self._result)
return self._handle_result() return self._handle_result()
...@@ -147,17 +150,20 @@ class TDengineCursor(object): ...@@ -147,17 +150,20 @@ class TDengineCursor(object):
buffer = [[] for i in range(len(self._fields))] buffer = [[] for i in range(len(self._fields))]
self._rowcount = 0 self._rowcount = 0
while True: while True:
block, num_of_fields = CTaosInterface.fetchRow(self._result, self._fields) block, num_of_fields = CTaosInterface.fetchRow(
self._result, self._fields)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno != 0: if errno != 0:
raise ProgrammingError(CTaosInterface.errStr(self._result), errno) raise ProgrammingError(
CTaosInterface.errStr(
self._result), errno)
if num_of_fields == 0: if num_of_fields == 0:
break break
self._rowcount += num_of_fields self._rowcount += num_of_fields
for i in range(len(self._fields)): for i in range(len(self._fields)):
buffer[i].extend(block[i]) buffer[i].extend(block[i])
return list(map(tuple, zip(*buffer))) return list(map(tuple, zip(*buffer)))
def fetchall(self): def fetchall(self):
if self._result is None or self._fields is None: if self._result is None or self._fields is None:
raise OperationalError("Invalid use of fetchall") raise OperationalError("Invalid use of fetchall")
...@@ -165,20 +171,21 @@ class TDengineCursor(object): ...@@ -165,20 +171,21 @@ class TDengineCursor(object):
buffer = [[] for i in range(len(self._fields))] buffer = [[] for i in range(len(self._fields))]
self._rowcount = 0 self._rowcount = 0
while True: while True:
block, num_of_fields = CTaosInterface.fetchBlock(self._result, self._fields) block, num_of_fields = CTaosInterface.fetchBlock(
self._result, self._fields)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno != 0: if errno != 0:
raise ProgrammingError(CTaosInterface.errStr(self._result), errno) raise ProgrammingError(
if num_of_fields == 0: break CTaosInterface.errStr(
self._result), errno)
if num_of_fields == 0:
break
self._rowcount += num_of_fields self._rowcount += num_of_fields
for i in range(len(self._fields)): for i in range(len(self._fields)):
buffer[i].extend(block[i]) buffer[i].extend(block[i])
return list(map(tuple, zip(*buffer))) return list(map(tuple, zip(*buffer)))
def nextset(self): def nextset(self):
""" """
""" """
...@@ -209,6 +216,7 @@ class TDengineCursor(object): ...@@ -209,6 +216,7 @@ class TDengineCursor(object):
""" """
self._description = [] self._description = []
for ele in self._fields: for ele in self._fields:
self._description.append((ele['name'], ele['type'], None, None, None, None, False)) self._description.append(
(ele['name'], ele['type'], None, None, None, None, False))
return self._result return self._result
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import time import time
import datetime import datetime
class DBAPITypeObject(object): class DBAPITypeObject(object):
def __init__(self, *values): def __init__(self, *values):
self.values = values self.values = values
...@@ -16,23 +17,28 @@ class DBAPITypeObject(object): ...@@ -16,23 +17,28 @@ class DBAPITypeObject(object):
else: else:
return -1 return -1
Date = datetime.date Date = datetime.date
Time = datetime.time Time = datetime.time
Timestamp = datetime.datetime Timestamp = datetime.datetime
def DataFromTicks(ticks): def DataFromTicks(ticks):
return Date(*time.localtime(ticks)[:3]) return Date(*time.localtime(ticks)[:3])
def TimeFromTicks(ticks): def TimeFromTicks(ticks):
return Time(*time.localtime(ticks)[3:6]) return Time(*time.localtime(ticks)[3:6])
def TimestampFromTicks(ticks): def TimestampFromTicks(ticks):
return Timestamp(*time.localtime(ticks)[:6]) return Timestamp(*time.localtime(ticks)[:6])
Binary = bytes Binary = bytes
# STRING = DBAPITypeObject(*constants.FieldType.get_string_types()) # STRING = DBAPITypeObject(*constants.FieldType.get_string_types())
# BINARY = DBAPITypeObject(*constants.FieldType.get_binary_types()) # BINARY = DBAPITypeObject(*constants.FieldType.get_binary_types())
# NUMBER = BAPITypeObject(*constants.FieldType.get_number_types()) # NUMBER = BAPITypeObject(*constants.FieldType.get_number_types())
# DATETIME = DBAPITypeObject(*constants.FieldType.get_timestamp_types()) # DATETIME = DBAPITypeObject(*constants.FieldType.get_timestamp_types())
# ROWID = DBAPITypeObject() # ROWID = DBAPITypeObject()
\ No newline at end of file
"""Python exceptions """Python exceptions
""" """
class Error(Exception): class Error(Exception):
def __init__(self, msg=None, errno=None): def __init__(self, msg=None, errno=None):
self.msg = msg self.msg = msg
self._full_msg = self.msg self._full_msg = self.msg
self.errno = errno self.errno = errno
def __str__(self): def __str__(self):
return self._full_msg return self._full_msg
class Warning(Exception): class Warning(Exception):
"""Exception raised for important warnings like data truncations while inserting. """Exception raised for important warnings like data truncations while inserting.
""" """
pass pass
class InterfaceError(Error): class InterfaceError(Error):
"""Exception raised for errors that are related to the database interface rather than the database itself. """Exception raised for errors that are related to the database interface rather than the database itself.
""" """
pass pass
class DatabaseError(Error): class DatabaseError(Error):
"""Exception raised for errors that are related to the database. """Exception raised for errors that are related to the database.
""" """
pass pass
class DataError(DatabaseError): class DataError(DatabaseError):
"""Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range. """Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range.
""" """
pass pass
class OperationalError(DatabaseError): class OperationalError(DatabaseError):
"""Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer """Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer
""" """
...@@ -41,17 +47,20 @@ class IntegrityError(DatabaseError): ...@@ -41,17 +47,20 @@ class IntegrityError(DatabaseError):
""" """
pass pass
class InternalError(DatabaseError): class InternalError(DatabaseError):
"""Exception raised when the database encounters an internal error. """Exception raised when the database encounters an internal error.
""" """
pass pass
class ProgrammingError(DatabaseError): class ProgrammingError(DatabaseError):
"""Exception raised for programming errors. """Exception raised for programming errors.
""" """
pass pass
class NotSupportedError(DatabaseError): class NotSupportedError(DatabaseError):
"""Exception raised in case a method or database API was used which is not supported by the database,. """Exception raised in case a method or database API was used which is not supported by the database,.
""" """
pass pass
\ No newline at end of file
from .cinterface import CTaosInterface from .cinterface import CTaosInterface
from .error import * from .error import *
class TDengineSubscription(object): class TDengineSubscription(object):
"""TDengine subscription object """TDengine subscription object
""" """
def __init__(self, sub): def __init__(self, sub):
self._sub = sub self._sub = sub
def consume(self): def consume(self):
"""Consume rows of a subscription """Consume rows of a subscription
""" """
if self._sub is None: if self._sub is None:
raise OperationalError("Invalid use of consume") raise OperationalError("Invalid use of consume")
result, fields = CTaosInterface.consume(self._sub) result, fields = CTaosInterface.consume(self._sub)
buffer = [[] for i in range(len(fields))] buffer = [[] for i in range(len(fields))]
while True: while True:
block, num_of_fields = CTaosInterface.fetchBlock(result, fields) block, num_of_fields = CTaosInterface.fetchBlock(result, fields)
if num_of_fields == 0: break if num_of_fields == 0:
break
for i in range(len(fields)): for i in range(len(fields)):
buffer[i].extend(block[i]) buffer[i].extend(block[i])
self.fields = fields self.fields = fields
return list(map(tuple, zip(*buffer))) return list(map(tuple, zip(*buffer)))
def close(self, keepProgress=True):
def close(self, keepProgress = True):
"""Close the Subscription. """Close the Subscription.
""" """
if self._sub is None: if self._sub is None:
...@@ -38,15 +39,19 @@ class TDengineSubscription(object): ...@@ -38,15 +39,19 @@ class TDengineSubscription(object):
if __name__ == '__main__': if __name__ == '__main__':
from .connection import TDengineConnection from .connection import TDengineConnection
conn = TDengineConnection(host="127.0.0.1", user="root", password="taosdata", database="test") conn = TDengineConnection(
host="127.0.0.1",
user="root",
password="taosdata",
database="test")
# Generate a cursor object to run SQL commands # Generate a cursor object to run SQL commands
sub = conn.subscribe(True, "test", "select * from meters;", 1000) sub = conn.subscribe(True, "test", "select * from meters;", 1000)
for i in range(0,10): for i in range(0, 10):
data = sub.consume() data = sub.consume()
for d in data: for d in data:
print(d) print(d)
sub.close() sub.close()
conn.close() conn.close()
\ No newline at end of file
...@@ -8,6 +8,7 @@ paramstyle = 'pyformat' ...@@ -8,6 +8,7 @@ paramstyle = 'pyformat'
__all__ = ['connection', 'cursor'] __all__ = ['connection', 'cursor']
def connect(*args, **kwargs): def connect(*args, **kwargs):
""" Function to return a TDengine connector object """ Function to return a TDengine connector object
......
...@@ -4,11 +4,14 @@ from .error import * ...@@ -4,11 +4,14 @@ from .error import *
import math import math
import datetime import datetime
def _convert_millisecond_to_datetime(milli): def _convert_millisecond_to_datetime(milli):
return datetime.datetime.fromtimestamp(milli/1000.0) return datetime.datetime.fromtimestamp(milli / 1000.0)
def _convert_microsecond_to_datetime(micro): def _convert_microsecond_to_datetime(micro):
return datetime.datetime.fromtimestamp(micro/1000000.0) return datetime.datetime.fromtimestamp(micro / 1000000.0)
def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bool row to python row """Function to convert C bool row to python row
...@@ -18,170 +21,309 @@ def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False): ...@@ -18,170 +21,309 @@ def _crow_timestamp_to_python(data, num_of_rows, nbytes=None, micro=False):
_timestamp_converter = _convert_microsecond_to_datetime _timestamp_converter = _convert_microsecond_to_datetime
if num_of_rows > 0: if num_of_rows > 0:
return list(map(_timestamp_converter, ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)])) return list(map(_timestamp_converter, ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]))
else: else:
return list(map(_timestamp_converter, ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)])) return list(map(_timestamp_converter, ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]))
def _crow_bool_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_bool_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bool row to python row """Function to convert C bool row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_byte))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_bool))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_BOOL_NULL else bool(ele) for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_bool))[
:abs(num_of_rows)]]
def _crow_tinyint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_tinyint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C tinyint row to python row """Function to convert C tinyint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_TINYINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_byte))[:abs(num_of_rows)]]
def _crow_tinyint_unsigned_to_python(
data,
num_of_rows,
nbytes=None,
micro=False):
"""Function to convert C tinyint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ubyte))[
:abs(num_of_rows)]]
else:
return [
None if ele == FieldType.C_TINYINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ubyte))[
:abs(num_of_rows)]]
def _crow_smallint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_smallint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C smallint row to python row """Function to convert C smallint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_short))[:abs(num_of_rows)]] return [
None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_short))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_short))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_SMALLINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_short))[
:abs(num_of_rows)]]
def _crow_smallint_unsigned_to_python(
data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C smallint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ushort))[
:abs(num_of_rows)]]
else:
return [
None if ele == FieldType.C_SMALLINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ushort))[
:abs(num_of_rows)]]
def _crow_int_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_int_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C int row to python row """Function to convert C int row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)]]
else:
return [None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)]]
def _crow_int_unsigned_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C int row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_uint))[
:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_INT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_int))[:abs(num_of_rows)] ] return [
None if ele == FieldType.C_INT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_uint))[
:abs(num_of_rows)]]
def _crow_bigint_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_bigint_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C bigint row to python row """Function to convert C bigint row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]]
else: else:
return [ None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_longlong))[:abs(num_of_rows)] ] return [None if ele == FieldType.C_BIGINT_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_long))[:abs(num_of_rows)]]
def _crow_bigint_unsigned_to_python(
data,
num_of_rows,
nbytes=None,
micro=False):
"""Function to convert C bigint row to python row
"""
if num_of_rows > 0:
return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ulong))[
:abs(num_of_rows)]]
else:
return [
None if ele == FieldType.C_BIGINT_UNSIGNED_NULL else ele for ele in ctypes.cast(
data, ctypes.POINTER(
ctypes.c_ulong))[
:abs(num_of_rows)]]
def _crow_float_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_float_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C float row to python row """Function to convert C float row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)]]
else: else:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_float))[:abs(num_of_rows)]]
def _crow_double_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_double_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C double row to python row """Function to convert C double row to python row
""" """
if num_of_rows > 0: if num_of_rows > 0:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)]]
else: else:
return [ None if math.isnan(ele) else ele for ele in ctypes.cast(data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)] ] return [None if math.isnan(ele) else ele for ele in ctypes.cast(
data, ctypes.POINTER(ctypes.c_double))[:abs(num_of_rows)]]
def _crow_binary_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_binary_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C binary row to python row """Function to convert C binary row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
if num_of_rows > 0: if num_of_rows > 0:
return [ None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode('utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]] return [None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode(
'utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]]
else: else:
return [ None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode('utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]] return [None if ele.value[0:1] == FieldType.C_BINARY_NULL else ele.value.decode(
'utf-8') for ele in (ctypes.cast(data, ctypes.POINTER(ctypes.c_char * nbytes)))[:abs(num_of_rows)]]
def _crow_nchar_to_python(data, num_of_rows, nbytes=None, micro=False): def _crow_nchar_to_python(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C nchar row to python row """Function to convert C nchar row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res = [] res = []
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
if num_of_rows >= 0: if num_of_rows >= 0:
tmpstr = ctypes.c_char_p(data) tmpstr = ctypes.c_char_p(data)
res.append( tmpstr.value.decode() ) res.append(tmpstr.value.decode())
else: else:
res.append( (ctypes.cast(data+nbytes*i, ctypes.POINTER(ctypes.c_wchar * (nbytes//4))))[0].value ) res.append((ctypes.cast(data + nbytes * i,
ctypes.POINTER(ctypes.c_wchar * (nbytes // 4))))[0].value)
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
def _crow_binary_to_python_block(data, num_of_rows, nbytes=None, micro=False): def _crow_binary_to_python_block(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C binary row to python row """Function to convert C binary row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res=[] res = []
if num_of_rows > 0: if num_of_rows > 0:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
rbyte=ctypes.cast(data+nbytes*i,ctypes.POINTER(ctypes.c_short))[:1].pop() rbyte = ctypes.cast(
tmpstr = ctypes.c_char_p(data+nbytes*i+2) data + nbytes * i,
res.append( tmpstr.value.decode()[0:rbyte] ) ctypes.POINTER(
ctypes.c_short))[
:1].pop()
tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append(tmpstr.value.decode()[0:rbyte])
except ValueError: except ValueError:
res.append(None) res.append(None)
else: else:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
rbyte=ctypes.cast(data+nbytes*i,ctypes.POINTER(ctypes.c_short))[:1].pop() rbyte = ctypes.cast(
tmpstr = ctypes.c_char_p(data+nbytes*i+2) data + nbytes * i,
res.append( tmpstr.value.decode()[0:rbyte] ) ctypes.POINTER(
ctypes.c_short))[
:1].pop()
tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append(tmpstr.value.decode()[0:rbyte])
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
def _crow_nchar_to_python_block(data, num_of_rows, nbytes=None, micro=False): def _crow_nchar_to_python_block(data, num_of_rows, nbytes=None, micro=False):
"""Function to convert C nchar row to python row """Function to convert C nchar row to python row
""" """
assert(nbytes is not None) assert(nbytes is not None)
res=[] res = []
if num_of_rows >= 0: if num_of_rows >= 0:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
tmpstr = ctypes.c_char_p(data+nbytes*i+2) tmpstr = ctypes.c_char_p(data + nbytes * i + 2)
res.append( tmpstr.value.decode() ) res.append(tmpstr.value.decode())
except ValueError: except ValueError:
res.append(None) res.append(None)
else: else:
for i in range(abs(num_of_rows)): for i in range(abs(num_of_rows)):
try: try:
res.append( (ctypes.cast(data+nbytes*i+2, ctypes.POINTER(ctypes.c_wchar * (nbytes//4))))[0].value ) res.append((ctypes.cast(data + nbytes * i + 2,
ctypes.POINTER(ctypes.c_wchar * (nbytes // 4))))[0].value)
except ValueError: except ValueError:
res.append(None) res.append(None)
return res return res
_CONVERT_FUNC = { _CONVERT_FUNC = {
FieldType.C_BOOL: _crow_bool_to_python, FieldType.C_BOOL: _crow_bool_to_python,
FieldType.C_TINYINT : _crow_tinyint_to_python, FieldType.C_TINYINT: _crow_tinyint_to_python,
FieldType.C_SMALLINT : _crow_smallint_to_python, FieldType.C_SMALLINT: _crow_smallint_to_python,
FieldType.C_INT : _crow_int_to_python, FieldType.C_INT: _crow_int_to_python,
FieldType.C_BIGINT : _crow_bigint_to_python, FieldType.C_BIGINT: _crow_bigint_to_python,
FieldType.C_FLOAT : _crow_float_to_python, FieldType.C_FLOAT: _crow_float_to_python,
FieldType.C_DOUBLE : _crow_double_to_python, FieldType.C_DOUBLE: _crow_double_to_python,
FieldType.C_BINARY: _crow_binary_to_python, FieldType.C_BINARY: _crow_binary_to_python,
FieldType.C_TIMESTAMP : _crow_timestamp_to_python, FieldType.C_TIMESTAMP: _crow_timestamp_to_python,
FieldType.C_NCHAR : _crow_nchar_to_python FieldType.C_NCHAR: _crow_nchar_to_python,
FieldType.C_TINYINT_UNSIGNED: _crow_tinyint_unsigned_to_python,
FieldType.C_SMALLINT_UNSIGNED: _crow_smallint_unsigned_to_python,
FieldType.C_INT_UNSIGNED: _crow_int_unsigned_to_python,
FieldType.C_BIGINT_UNSIGNED: _crow_bigint_unsigned_to_python
} }
_CONVERT_FUNC_BLOCK = { _CONVERT_FUNC_BLOCK = {
FieldType.C_BOOL: _crow_bool_to_python, FieldType.C_BOOL: _crow_bool_to_python,
FieldType.C_TINYINT : _crow_tinyint_to_python, FieldType.C_TINYINT: _crow_tinyint_to_python,
FieldType.C_SMALLINT : _crow_smallint_to_python, FieldType.C_SMALLINT: _crow_smallint_to_python,
FieldType.C_INT : _crow_int_to_python, FieldType.C_INT: _crow_int_to_python,
FieldType.C_BIGINT : _crow_bigint_to_python, FieldType.C_BIGINT: _crow_bigint_to_python,
FieldType.C_FLOAT : _crow_float_to_python, FieldType.C_FLOAT: _crow_float_to_python,
FieldType.C_DOUBLE : _crow_double_to_python, FieldType.C_DOUBLE: _crow_double_to_python,
FieldType.C_BINARY: _crow_binary_to_python_block, FieldType.C_BINARY: _crow_binary_to_python_block,
FieldType.C_TIMESTAMP : _crow_timestamp_to_python, FieldType.C_TIMESTAMP: _crow_timestamp_to_python,
FieldType.C_NCHAR : _crow_nchar_to_python_block FieldType.C_NCHAR: _crow_nchar_to_python_block,
FieldType.C_TINYINT_UNSIGNED: _crow_tinyint_unsigned_to_python,
FieldType.C_SMALLINT_UNSIGNED: _crow_smallint_unsigned_to_python,
FieldType.C_INT_UNSIGNED: _crow_int_unsigned_to_python,
FieldType.C_BIGINT_UNSIGNED: _crow_bigint_unsigned_to_python
} }
# Corresponding TAOS_FIELD structure in C # Corresponding TAOS_FIELD structure in C
class TaosField(ctypes.Structure): class TaosField(ctypes.Structure):
_fields_ = [('name', ctypes.c_char * 65), _fields_ = [('name', ctypes.c_char * 65),
('type', ctypes.c_char), ('type', ctypes.c_char),
('bytes', ctypes.c_short)] ('bytes', ctypes.c_short)]
# C interface class # C interface class
class CTaosInterface(object): class CTaosInterface(object):
libtaos = ctypes.windll.LoadLibrary('taos') libtaos = ctypes.windll.LoadLibrary('taos')
...@@ -218,7 +360,7 @@ class CTaosInterface(object): ...@@ -218,7 +360,7 @@ class CTaosInterface(object):
except AttributeError: except AttributeError:
raise AttributeError("config is expected as a str") raise AttributeError("config is expected as a str")
if config != None: if config is not None:
CTaosInterface.libtaos.taos_options(3, self._config) CTaosInterface.libtaos.taos_options(3, self._config)
CTaosInterface.libtaos.taos_init() CTaosInterface.libtaos.taos_init()
...@@ -229,7 +371,13 @@ class CTaosInterface(object): ...@@ -229,7 +371,13 @@ class CTaosInterface(object):
""" """
return self._config return self._config
def connect(self, host=None, user="root", password="taosdata", db=None, port=0): def connect(
self,
host=None,
user="root",
password="taosdata",
db=None,
port=0):
''' '''
Function to connect to server Function to connect to server
...@@ -238,7 +386,7 @@ class CTaosInterface(object): ...@@ -238,7 +386,7 @@ class CTaosInterface(object):
# host # host
try: try:
_host = ctypes.c_char_p(host.encode( _host = ctypes.c_char_p(host.encode(
"utf-8")) if host != None else ctypes.c_char_p(None) "utf-8")) if host is not None else ctypes.c_char_p(None)
except AttributeError: except AttributeError:
raise AttributeError("host is expected as a str") raise AttributeError("host is expected as a str")
...@@ -257,7 +405,7 @@ class CTaosInterface(object): ...@@ -257,7 +405,7 @@ class CTaosInterface(object):
# db # db
try: try:
_db = ctypes.c_char_p( _db = ctypes.c_char_p(
db.encode("utf-8")) if db != None else ctypes.c_char_p(None) db.encode("utf-8")) if db is not None else ctypes.c_char_p(None)
except AttributeError: except AttributeError:
raise AttributeError("db is expected as a str") raise AttributeError("db is expected as a str")
...@@ -270,11 +418,11 @@ class CTaosInterface(object): ...@@ -270,11 +418,11 @@ class CTaosInterface(object):
connection = ctypes.c_void_p(CTaosInterface.libtaos.taos_connect( connection = ctypes.c_void_p(CTaosInterface.libtaos.taos_connect(
_host, _user, _password, _db, _port)) _host, _user, _password, _db, _port))
if connection.value == None: if connection.value is None:
print('connect to TDengine failed') print('connect to TDengine failed')
raise ConnectionError("connect to TDengine failed") raise ConnectionError("connect to TDengine failed")
# sys.exit(1) # sys.exit(1)
#else: # else:
# print('connect to TDengine success') # print('connect to TDengine success')
return connection return connection
...@@ -295,7 +443,8 @@ class CTaosInterface(object): ...@@ -295,7 +443,8 @@ class CTaosInterface(object):
@rtype: 0 on success and -1 on failure @rtype: 0 on success and -1 on failure
''' '''
try: try:
return CTaosInterface.libtaos.taos_query(connection, ctypes.c_char_p(sql.encode('utf-8'))) return CTaosInterface.libtaos.taos_query(
connection, ctypes.c_char_p(sql.encode('utf-8')))
except AttributeError: except AttributeError:
raise AttributeError("sql is expected as a string") raise AttributeError("sql is expected as a string")
# finally: # finally:
...@@ -310,7 +459,7 @@ class CTaosInterface(object): ...@@ -310,7 +459,7 @@ class CTaosInterface(object):
@staticmethod @staticmethod
def subscribe(connection, restart, topic, sql, interval): def subscribe(connection, restart, topic, sql, interval):
"""Create a subscription """Create a subscription
@restart boolean, @restart boolean,
@sql string, sql statement for data query, must be a 'select' statement. @sql string, sql statement for data query, must be a 'select' statement.
@topic string, name of this subscription @topic string, name of this subscription
""" """
...@@ -362,35 +511,49 @@ class CTaosInterface(object): ...@@ -362,35 +511,49 @@ class CTaosInterface(object):
result, ctypes.byref(pblock)) result, ctypes.byref(pblock))
if num_of_rows == 0: if num_of_rows == 0:
return None, 0 return None, 0
isMicro = (CTaosInterface.libtaos.taos_result_precision(result) == FieldType.C_TIMESTAMP_MICRO) isMicro = (CTaosInterface.libtaos.taos_result_precision(
result) == FieldType.C_TIMESTAMP_MICRO)
blocks = [None] * len(fields) blocks = [None] * len(fields)
fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result) fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result)
fieldLen = [ele for ele in ctypes.cast(fieldL, ctypes.POINTER(ctypes.c_int))[:len(fields)]] fieldLen = [
ele for ele in ctypes.cast(
fieldL, ctypes.POINTER(
ctypes.c_int))[
:len(fields)]]
for i in range(len(fields)): for i in range(len(fields)):
data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i] data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i]
if fields[i]['type'] not in _CONVERT_FUNC_BLOCK: if fields[i]['type'] not in _CONVERT_FUNC_BLOCK:
raise DatabaseError("Invalid data type returned from database") raise DatabaseError("Invalid data type returned from database")
blocks[i] = _CONVERT_FUNC_BLOCK[fields[i]['type']](data, num_of_rows, fieldLen[i], isMicro) blocks[i] = _CONVERT_FUNC_BLOCK[fields[i]['type']](
data, num_of_rows, fieldLen[i], isMicro)
return blocks, abs(num_of_rows) return blocks, abs(num_of_rows)
@staticmethod @staticmethod
def fetchRow(result, fields): def fetchRow(result, fields):
pblock = ctypes.c_void_p(0) pblock = ctypes.c_void_p(0)
pblock = CTaosInterface.libtaos.taos_fetch_row(result) pblock = CTaosInterface.libtaos.taos_fetch_row(result)
if pblock : if pblock:
num_of_rows = 1 num_of_rows = 1
isMicro = (CTaosInterface.libtaos.taos_result_precision(result) == FieldType.C_TIMESTAMP_MICRO) isMicro = (CTaosInterface.libtaos.taos_result_precision(
result) == FieldType.C_TIMESTAMP_MICRO)
blocks = [None] * len(fields) blocks = [None] * len(fields)
fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result) fieldL = CTaosInterface.libtaos.taos_fetch_lengths(result)
fieldLen = [ele for ele in ctypes.cast(fieldL, ctypes.POINTER(ctypes.c_int))[:len(fields)]] fieldLen = [
ele for ele in ctypes.cast(
fieldL, ctypes.POINTER(
ctypes.c_int))[
:len(fields)]]
for i in range(len(fields)): for i in range(len(fields)):
data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i] data = ctypes.cast(pblock, ctypes.POINTER(ctypes.c_void_p))[i]
if fields[i]['type'] not in _CONVERT_FUNC: if fields[i]['type'] not in _CONVERT_FUNC:
raise DatabaseError("Invalid data type returned from database") raise DatabaseError(
"Invalid data type returned from database")
if data is None: if data is None:
blocks[i] = [None] blocks[i] = [None]
else: else:
blocks[i] = _CONVERT_FUNC[fields[i]['type']](data, num_of_rows, fieldLen[i], isMicro) blocks[i] = _CONVERT_FUNC[fields[i]['type']](
data, num_of_rows, fieldLen[i], isMicro)
else: else:
return None, 0 return None, 0
return blocks, abs(num_of_rows) return blocks, abs(num_of_rows)
...@@ -476,4 +639,4 @@ if __name__ == '__main__': ...@@ -476,4 +639,4 @@ if __name__ == '__main__':
print(data) print(data)
cinter.freeResult(result) cinter.freeResult(result)
cinter.close(conn) cinter.close(conn)
\ No newline at end of file
...@@ -2,9 +2,11 @@ from .cursor import TDengineCursor ...@@ -2,9 +2,11 @@ from .cursor import TDengineCursor
from .subscription import TDengineSubscription from .subscription import TDengineSubscription
from .cinterface import CTaosInterface from .cinterface import CTaosInterface
class TDengineConnection(object): class TDengineConnection(object):
""" TDengine connection object """ TDengine connection object
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._conn = None self._conn = None
self._host = None self._host = None
...@@ -30,7 +32,7 @@ class TDengineConnection(object): ...@@ -30,7 +32,7 @@ class TDengineConnection(object):
# password # password
if 'password' in kwargs: if 'password' in kwargs:
self._password = kwargs['password'] self._password = kwargs['password']
# database # database
if 'database' in kwargs: if 'database' in kwargs:
self._database = kwargs['database'] self._database = kwargs['database']
...@@ -44,7 +46,12 @@ class TDengineConnection(object): ...@@ -44,7 +46,12 @@ class TDengineConnection(object):
self._config = kwargs['config'] self._config = kwargs['config']
self._chandle = CTaosInterface(self._config) self._chandle = CTaosInterface(self._config)
self._conn = self._chandle.connect(self._host, self._user, self._password, self._database, self._port) self._conn = self._chandle.connect(
self._host,
self._user,
self._password,
self._database,
self._port)
def close(self): def close(self):
"""Close current connection. """Close current connection.
...@@ -56,7 +63,8 @@ class TDengineConnection(object): ...@@ -56,7 +63,8 @@ class TDengineConnection(object):
""" """
if self._conn is None: if self._conn is None:
return None return None
sub = CTaosInterface.subscribe(self._conn, restart, topic, sql, interval) sub = CTaosInterface.subscribe(
self._conn, restart, topic, sql, interval)
return TDengineSubscription(sub) return TDengineSubscription(sub)
def cursor(self): def cursor(self):
...@@ -81,7 +89,8 @@ class TDengineConnection(object): ...@@ -81,7 +89,8 @@ class TDengineConnection(object):
""" """
pass pass
if __name__ == "__main__": if __name__ == "__main__":
conn = TDengineConnection(host='192.168.1.107') conn = TDengineConnection(host='192.168.1.107')
conn.close() conn.close()
print("Hello world") print("Hello world")
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
from .dbapi import * from .dbapi import *
class FieldType(object): class FieldType(object):
"""TDengine Field Types """TDengine Field Types
""" """
...@@ -18,13 +19,21 @@ class FieldType(object): ...@@ -18,13 +19,21 @@ class FieldType(object):
C_BINARY = 8 C_BINARY = 8
C_TIMESTAMP = 9 C_TIMESTAMP = 9
C_NCHAR = 10 C_NCHAR = 10
C_TINYINT_UNSIGNED = 11
C_SMALLINT_UNSIGNED = 12
C_INT_UNSIGNED = 13
C_BIGINT_UNSIGNED = 14
# NULL value definition # NULL value definition
# NOTE: These values should change according to C definition in tsdb.h # NOTE: These values should change according to C definition in tsdb.h
C_BOOL_NULL = 0x02 C_BOOL_NULL = 0x02
C_TINYINT_NULL = -128 C_TINYINT_NULL = -128
C_TINYINT_UNSIGNED_NULL = 255
C_SMALLINT_NULL = -32768 C_SMALLINT_NULL = -32768
C_SMALLINT_UNSIGNED_NULL = 65535
C_INT_NULL = -2147483648 C_INT_NULL = -2147483648
C_INT_UNSIGNED_NULL = 4294967295
C_BIGINT_NULL = -9223372036854775808 C_BIGINT_NULL = -9223372036854775808
C_BIGINT_UNSIGNED_NULL = 18446744073709551615
C_FLOAT_NULL = float('nan') C_FLOAT_NULL = float('nan')
C_DOUBLE_NULL = float('nan') C_DOUBLE_NULL = float('nan')
C_BINARY_NULL = bytearray([int('0xff', 16)]) C_BINARY_NULL = bytearray([int('0xff', 16)])
......
...@@ -24,7 +24,7 @@ class TDengineCursor(object): ...@@ -24,7 +24,7 @@ class TDengineCursor(object):
if the cursor has not had an operation invoked via the .execute*() method yet. if the cursor has not had an operation invoked via the .execute*() method yet.
.rowcount:This read-only attribute specifies the number of rows that the last .rowcount:This read-only attribute specifies the number of rows that the last
.execute*() produced (for DQL statements like SELECT) or affected .execute*() produced (for DQL statements like SELECT) or affected
""" """
def __init__(self, connection=None): def __init__(self, connection=None):
...@@ -51,13 +51,14 @@ class TDengineCursor(object): ...@@ -51,13 +51,14 @@ class TDengineCursor(object):
raise OperationalError("Invalid use of fetch iterator") raise OperationalError("Invalid use of fetch iterator")
if self._block_rows <= self._block_iter: if self._block_rows <= self._block_iter:
block, self._block_rows = CTaosInterface.fetchRow(self._result, self._fields) block, self._block_rows = CTaosInterface.fetchRow(
self._result, self._fields)
if self._block_rows == 0: if self._block_rows == 0:
raise StopIteration raise StopIteration
self._block = list(map(tuple, zip(*block))) self._block = list(map(tuple, zip(*block)))
self._block_iter = 0 self._block_iter = 0
data = self._block[self._block_iter] data = self._block[self._block_iter]
self._block_iter += 1 self._block_iter += 1
return data return data
...@@ -92,7 +93,7 @@ class TDengineCursor(object): ...@@ -92,7 +93,7 @@ class TDengineCursor(object):
""" """
if self._connection is None: if self._connection is None:
return False return False
self._reset_result() self._reset_result()
self._connection = None self._connection = None
...@@ -107,24 +108,25 @@ class TDengineCursor(object): ...@@ -107,24 +108,25 @@ class TDengineCursor(object):
if not self._connection: if not self._connection:
# TODO : change the exception raised here # TODO : change the exception raised here
raise ProgrammingError("Cursor is not connected") raise ProgrammingError("Cursor is not connected")
self._reset_result() self._reset_result()
stmt = operation stmt = operation
if params is not None: if params is not None:
pass pass
self._result = CTaosInterface.query(self._connection._conn, stmt) self._result = CTaosInterface.query(self._connection._conn, stmt)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno == 0: if errno == 0:
if CTaosInterface.fieldsCount(self._result) == 0: if CTaosInterface.fieldsCount(self._result) == 0:
self._affected_rows += CTaosInterface.affectedRows(self._result ) self._affected_rows += CTaosInterface.affectedRows(
return CTaosInterface.affectedRows(self._result ) self._result)
return CTaosInterface.affectedRows(self._result)
else: else:
self._fields = CTaosInterface.useResult(self._result ) self._fields = CTaosInterface.useResult(self._result)
return self._handle_result() return self._handle_result()
else: else:
raise ProgrammingError(CTaosInterface.errStr(self._result ), errno) raise ProgrammingError(CTaosInterface.errStr(self._result), errno)
def executemany(self, operation, seq_of_parameters): def executemany(self, operation, seq_of_parameters):
"""Prepare a database operation (query or command) and then execute it against all parameter sequences or mappings found in the sequence seq_of_parameters. """Prepare a database operation (query or command) and then execute it against all parameter sequences or mappings found in the sequence seq_of_parameters.
...@@ -148,10 +150,13 @@ class TDengineCursor(object): ...@@ -148,10 +150,13 @@ class TDengineCursor(object):
buffer = [[] for i in range(len(self._fields))] buffer = [[] for i in range(len(self._fields))]
self._rowcount = 0 self._rowcount = 0
while True: while True:
block, num_of_fields = CTaosInterface.fetchRow(self._result, self._fields) block, num_of_fields = CTaosInterface.fetchRow(
self._result, self._fields)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno != 0: if errno != 0:
raise ProgrammingError(CTaosInterface.errStr(self._result), errno) raise ProgrammingError(
CTaosInterface.errStr(
self._result), errno)
if num_of_fields == 0: if num_of_fields == 0:
break break
self._rowcount += num_of_fields self._rowcount += num_of_fields
...@@ -166,20 +171,21 @@ class TDengineCursor(object): ...@@ -166,20 +171,21 @@ class TDengineCursor(object):
buffer = [[] for i in range(len(self._fields))] buffer = [[] for i in range(len(self._fields))]
self._rowcount = 0 self._rowcount = 0
while True: while True:
block, num_of_fields = CTaosInterface.fetchBlock(self._result, self._fields) block, num_of_fields = CTaosInterface.fetchBlock(
self._result, self._fields)
errno = CTaosInterface.libtaos.taos_errno(self._result) errno = CTaosInterface.libtaos.taos_errno(self._result)
if errno != 0: if errno != 0:
raise ProgrammingError(CTaosInterface.errStr(self._result), errno) raise ProgrammingError(
if num_of_fields == 0: break CTaosInterface.errStr(
self._result), errno)
if num_of_fields == 0:
break
self._rowcount += num_of_fields self._rowcount += num_of_fields
for i in range(len(self._fields)): for i in range(len(self._fields)):
buffer[i].extend(block[i]) buffer[i].extend(block[i])
return list(map(tuple, zip(*buffer))) return list(map(tuple, zip(*buffer)))
def nextset(self): def nextset(self):
""" """
""" """
...@@ -204,12 +210,13 @@ class TDengineCursor(object): ...@@ -204,12 +210,13 @@ class TDengineCursor(object):
self._block_rows = -1 self._block_rows = -1
self._block_iter = 0 self._block_iter = 0
self._affected_rows = 0 self._affected_rows = 0
def _handle_result(self): def _handle_result(self):
"""Handle the return result from query. """Handle the return result from query.
""" """
self._description = [] self._description = []
for ele in self._fields: for ele in self._fields:
self._description.append((ele['name'], ele['type'], None, None, None, None, False)) self._description.append(
(ele['name'], ele['type'], None, None, None, None, False))
return self._result return self._result
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import time import time
import datetime import datetime
class DBAPITypeObject(object): class DBAPITypeObject(object):
def __init__(self, *values): def __init__(self, *values):
self.values = values self.values = values
...@@ -16,23 +17,28 @@ class DBAPITypeObject(object): ...@@ -16,23 +17,28 @@ class DBAPITypeObject(object):
else: else:
return -1 return -1
Date = datetime.date Date = datetime.date
Time = datetime.time Time = datetime.time
Timestamp = datetime.datetime Timestamp = datetime.datetime
def DataFromTicks(ticks): def DataFromTicks(ticks):
return Date(*time.localtime(ticks)[:3]) return Date(*time.localtime(ticks)[:3])
def TimeFromTicks(ticks): def TimeFromTicks(ticks):
return Time(*time.localtime(ticks)[3:6]) return Time(*time.localtime(ticks)[3:6])
def TimestampFromTicks(ticks): def TimestampFromTicks(ticks):
return Timestamp(*time.localtime(ticks)[:6]) return Timestamp(*time.localtime(ticks)[:6])
Binary = bytes Binary = bytes
# STRING = DBAPITypeObject(*constants.FieldType.get_string_types()) # STRING = DBAPITypeObject(*constants.FieldType.get_string_types())
# BINARY = DBAPITypeObject(*constants.FieldType.get_binary_types()) # BINARY = DBAPITypeObject(*constants.FieldType.get_binary_types())
# NUMBER = BAPITypeObject(*constants.FieldType.get_number_types()) # NUMBER = BAPITypeObject(*constants.FieldType.get_number_types())
# DATETIME = DBAPITypeObject(*constants.FieldType.get_timestamp_types()) # DATETIME = DBAPITypeObject(*constants.FieldType.get_timestamp_types())
# ROWID = DBAPITypeObject() # ROWID = DBAPITypeObject()
\ No newline at end of file
"""Python exceptions """Python exceptions
""" """
class Error(Exception): class Error(Exception):
def __init__(self, msg=None, errno=None): def __init__(self, msg=None, errno=None):
self.msg = msg self.msg = msg
self._full_msg = self.msg self._full_msg = self.msg
self.errno = errno self.errno = errno
def __str__(self): def __str__(self):
return self._full_msg return self._full_msg
class Warning(Exception): class Warning(Exception):
"""Exception raised for important warnings like data truncations while inserting. """Exception raised for important warnings like data truncations while inserting.
""" """
pass pass
class InterfaceError(Error): class InterfaceError(Error):
"""Exception raised for errors that are related to the database interface rather than the database itself. """Exception raised for errors that are related to the database interface rather than the database itself.
""" """
pass pass
class DatabaseError(Error): class DatabaseError(Error):
"""Exception raised for errors that are related to the database. """Exception raised for errors that are related to the database.
""" """
pass pass
class DataError(DatabaseError): class DataError(DatabaseError):
"""Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range. """Exception raised for errors that are due to problems with the processed data like division by zero, numeric value out of range.
""" """
pass pass
class OperationalError(DatabaseError): class OperationalError(DatabaseError):
"""Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer """Exception raised for errors that are related to the database's operation and not necessarily under the control of the programmer
""" """
...@@ -41,17 +47,20 @@ class IntegrityError(DatabaseError): ...@@ -41,17 +47,20 @@ class IntegrityError(DatabaseError):
""" """
pass pass
class InternalError(DatabaseError): class InternalError(DatabaseError):
"""Exception raised when the database encounters an internal error. """Exception raised when the database encounters an internal error.
""" """
pass pass
class ProgrammingError(DatabaseError): class ProgrammingError(DatabaseError):
"""Exception raised for programming errors. """Exception raised for programming errors.
""" """
pass pass
class NotSupportedError(DatabaseError): class NotSupportedError(DatabaseError):
"""Exception raised in case a method or database API was used which is not supported by the database,. """Exception raised in case a method or database API was used which is not supported by the database,.
""" """
pass pass
\ No newline at end of file
from .cinterface import CTaosInterface from .cinterface import CTaosInterface
from .error import * from .error import *
class TDengineSubscription(object): class TDengineSubscription(object):
"""TDengine subscription object """TDengine subscription object
""" """
def __init__(self, sub): def __init__(self, sub):
self._sub = sub self._sub = sub
def consume(self): def consume(self):
"""Consume rows of a subscription """Consume rows of a subscription
""" """
if self._sub is None: if self._sub is None:
raise OperationalError("Invalid use of consume") raise OperationalError("Invalid use of consume")
result, fields = CTaosInterface.consume(self._sub) result, fields = CTaosInterface.consume(self._sub)
buffer = [[] for i in range(len(fields))] buffer = [[] for i in range(len(fields))]
while True: while True:
block, num_of_fields = CTaosInterface.fetchBlock(result, fields) block, num_of_fields = CTaosInterface.fetchBlock(result, fields)
if num_of_fields == 0: break if num_of_fields == 0:
break
for i in range(len(fields)): for i in range(len(fields)):
buffer[i].extend(block[i]) buffer[i].extend(block[i])
self.fields = fields self.fields = fields
return list(map(tuple, zip(*buffer))) return list(map(tuple, zip(*buffer)))
def close(self, keepProgress=True):
def close(self, keepProgress = True):
"""Close the Subscription. """Close the Subscription.
""" """
if self._sub is None: if self._sub is None:
...@@ -38,15 +39,19 @@ class TDengineSubscription(object): ...@@ -38,15 +39,19 @@ class TDengineSubscription(object):
if __name__ == '__main__': if __name__ == '__main__':
from .connection import TDengineConnection from .connection import TDengineConnection
conn = TDengineConnection(host="127.0.0.1", user="root", password="taosdata", database="test") conn = TDengineConnection(
host="127.0.0.1",
user="root",
password="taosdata",
database="test")
# Generate a cursor object to run SQL commands # Generate a cursor object to run SQL commands
sub = conn.subscribe(True, "test", "select * from meters;", 1000) sub = conn.subscribe(True, "test", "select * from meters;", 1000)
for i in range(0,10): for i in range(0, 10):
data = sub.consume() data = sub.consume()
for d in data: for d in data:
print(d) print(d)
sub.close() sub.close()
conn.close() conn.close()
\ No newline at end of file
...@@ -26,7 +26,7 @@ class TDTestCase: ...@@ -26,7 +26,7 @@ class TDTestCase:
tdSql.prepare() tdSql.prepare()
ret = tdSql.execute( ret = tdSql.execute(
'create table tb (ts timestamp, speed int unsigned)') 'create table tb (ts timestamp, speed tinyint unsigned)')
insertRows = 10 insertRows = 10
tdLog.info("insert %d rows" % (insertRows)) tdLog.info("insert %d rows" % (insertRows))
...@@ -38,11 +38,11 @@ class TDTestCase: ...@@ -38,11 +38,11 @@ class TDTestCase:
tdLog.info("insert earlier data") tdLog.info("insert earlier data")
tdSql.execute('insert into tb values (now - 5m , 10)') tdSql.execute('insert into tb values (now - 5m , 10)')
tdSql.execute('insert into tb values (now - 6m , 10)') tdSql.execute('insert into tb values (now - 6m , 10)')
tdSql.execute('insert into tb values (now - 7m , 10)') tdSql.execute('insert into tb values (now - 7m , NULL)')
tdSql.execute('insert into tb values (now - 8m , 4294967294)') tdSql.execute('insert into tb values (now - 8m , 254)')
tdSql.error('insert into tb values (now - 9m, -1)') tdSql.error('insert into tb values (now - 9m, -1)')
tdSql.error('insert into tb values (now - 9m, 4294967295)') tdSql.error('insert into tb values (now - 9m, 255)')
tdSql.query("select * from tb") tdSql.query("select * from tb")
tdSql.checkRows(insertRows + 4) tdSql.checkRows(insertRows + 4)
......
...@@ -16,7 +16,7 @@ python3 ./test.py -f insert/nchar.py ...@@ -16,7 +16,7 @@ python3 ./test.py -f insert/nchar.py
python3 ./test.py -f insert/nchar-unicode.py python3 ./test.py -f insert/nchar-unicode.py
python3 ./test.py -f insert/multi.py python3 ./test.py -f insert/multi.py
python3 ./test.py -f insert/randomNullCommit.py python3 ./test.py -f insert/randomNullCommit.py
#python3 insert/retentionpolicy.py python3 insert/retentionpolicy.py
python3 ./test.py -f insert/alterTableAndInsert.py python3 ./test.py -f insert/alterTableAndInsert.py
python3 ./test.py -f insert/insertIntoTwoTables.py python3 ./test.py -f insert/insertIntoTwoTables.py
python3 ./test.py -f insert/before_1970.py python3 ./test.py -f insert/before_1970.py
......
...@@ -23,4 +23,11 @@ python3 ./test.py -f functions/function_sum.py -r 1 ...@@ -23,4 +23,11 @@ python3 ./test.py -f functions/function_sum.py -r 1
python3 ./test.py -f functions/function_top.py -r 1 python3 ./test.py -f functions/function_top.py -r 1
python3 ./test.py -f functions/function_twa.py -r 1 python3 ./test.py -f functions/function_twa.py -r 1
python3 ./test.py -f functions/function_twa_test2.py python3 ./test.py -f functions/function_twa_test2.py
python3 ./test.py -f functions/function_stddev_td2555.pyhao python3 ./test.py -f functions/function_stddev_td2555.py
\ No newline at end of file python3 ./test.py -f insert/metadataUpdate.py
python3 ./test.py -f tools/taosdemoTest2.py
python3 ./test.py -f query/last_cache.py
python3 ./test.py -f query/last_row_cache.py
python3 ./test.py -f account/account_create.py
python3 ./test.py -f alter/alter_table.py
python3 ./test.py -f query/queryGroupbySort.py
\ No newline at end of file
...@@ -37,4 +37,10 @@ ...@@ -37,4 +37,10 @@
./test.sh -f general/stable/values.sim ./test.sh -f general/stable/values.sim
./test.sh -f general/stable/vnode3.sim ./test.sh -f general/stable/vnode3.sim
./test.sh -f unique/column/replica3.sim ./test.sh -f unique/column/replica3.sim
\ No newline at end of file ./test.sh -f issue/TD-2713.sim
./test.sh -f general/parser/select_distinct_tag.sim
./test.sh -f unique/mnode/mgmt30.sim
./test.sh -f issue/TD-2677.sim
./test.sh -f issue/TD-2680.sim
./test.sh -f unique/dnode/lossdata.sim
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册