Skip to content

Commit 73cd399

Browse files
authored
feat(ws): support DECIMAL data type (#388)
1 parent 68c84f8 commit 73cd399

18 files changed

Lines changed: 539 additions & 88 deletions

.github/workflows/taos-ws-py-enterprise.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ jobs:
8585
run: pip install taos-ws-py --no-index --force-reinstall --find-links taos-ws-py/target/wheels
8686

8787
- name: Get TDengine
88-
run: wget "${{ secrets.NIGHTLY_TDENGINE_ENTERPRISE_BASE_URL }}/tsdb-nightly-3.0.tar.gz?v=$(date +%s)" -O tsdb-nightly-3.0.tar.gz
88+
run: wget "${{ secrets.NIGHTLY_TDENGINE_ENTERPRISE_BASE_URL }}/tsdb-nightly-main.tar.gz?v=$(date +%s)" -O tsdb-nightly-main.tar.gz
8989

9090
- name: Install TDengine
9191
run: |
92-
tar -zxf tsdb-nightly-3.0.tar.gz
93-
rm -rf tsdb-nightly-3.0.tar.gz
94-
cd tsdb-nightly-3.0
92+
tar -zxf tsdb-nightly-main.tar.gz
93+
rm -rf tsdb-nightly-main.tar.gz
94+
cd tsdb-nightly-main
9595
sudo ./install.sh
9696
9797
- name: Copy taos.cfg

taos-ws-py/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Conventional Changelog](https://www.conventionalcommits.org/en/v1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## v0.6.8 - 2026-04-09
9+
10+
### Features:
11+
12+
- Support DECIMAL data type
13+
814
## v0.6.7 - 2026-03-31
915

1016
### Enhancements:

taos-ws-py/Cargo.lock

Lines changed: 9 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

taos-ws-py/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "taos-ws-py"
3-
version = "0.6.7"
3+
version = "0.6.8"
44
edition = "2021"
55
publish = false
66
license = "MIT"
@@ -11,6 +11,7 @@ crate-type = ["cdylib"]
1111

1212
[dependencies]
1313
anyhow = "1"
14+
bigdecimal = "0.4"
1415
chrono = "0.4"
1516
chrono-tz = "0.10.4"
1617
iana-time-zone = "0.1.63"

taos-ws-py/src/common.rs

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ use taos::{taos_query::common::Timestamp, BorrowedValue, RawBlock};
1111

1212
use crate::ConsumerException;
1313

14+
pub fn to_py_decimal(value: impl std::fmt::Display, py: Python<'_>) -> PyResult<PyObject> {
15+
let decimal_mod = py.import("decimal")?;
16+
let decimal_cls = decimal_mod.getattr("Decimal")?;
17+
let decimal = value.to_string();
18+
Ok(decimal_cls.call1((decimal,))?.into_py(py))
19+
}
20+
1421
pub fn to_py_datetime(ts: Timestamp, tz: Option<Tz>, py: Python) -> PyResult<PyObject> {
1522
let datetime_mod = py.import("datetime")?;
1623
let datetime = datetime_mod.getattr("datetime")?;
@@ -94,7 +101,11 @@ fn warn_missing_timezone_libs(tz: Option<Tz>) {
94101
});
95102
}
96103

97-
pub unsafe fn get_row_of_block_unchecked(py: Python, block: &RawBlock, index: usize) -> PyObject {
104+
pub unsafe fn get_row_of_block_unchecked(
105+
py: Python,
106+
block: &RawBlock,
107+
index: usize,
108+
) -> PyResult<PyObject> {
98109
let mut vec = Vec::new();
99110
for i in 0..block.ncols() {
100111
let val = block.get_ref(index, i).unwrap();
@@ -110,43 +121,44 @@ pub unsafe fn get_row_of_block_unchecked(py: Python, block: &RawBlock, index: us
110121
BorrowedValue::VarChar(v) => v.into_py(py),
111122
BorrowedValue::Timestamp(v) => match v.precision() {
112123
taos::Precision::Nanosecond => v.as_raw_i64().to_object(py),
113-
_ => to_py_datetime(v, block.timezone(), py).unwrap(),
124+
_ => to_py_datetime(v, block.timezone(), py)?,
114125
},
115126
BorrowedValue::NChar(v) => v.into_py(py),
116127
BorrowedValue::UTinyInt(v) => v.into_py(py),
117128
BorrowedValue::USmallInt(v) => v.into_py(py),
118129
BorrowedValue::UInt(v) => v.into_py(py),
119130
BorrowedValue::UBigInt(v) => v.into_py(py),
120131
BorrowedValue::Json(v) => std::str::from_utf8(&v)
121-
.map_err(|err| ConsumerException::new_err(err.to_string()))
122-
.unwrap()
132+
.map_err(|err| ConsumerException::new_err(err.to_string()))?
123133
.to_string()
124134
.into_py(py),
125135
BorrowedValue::VarBinary(v) => v.into_py(py),
126136
BorrowedValue::Geometry(v) => v.into_py(py),
127-
BorrowedValue::Decimal64(v) => v.to_string().into_py(py),
128-
BorrowedValue::Decimal(v) => v.to_string().into_py(py),
137+
BorrowedValue::Decimal64(v) => to_py_decimal(v, py)?,
138+
BorrowedValue::Decimal(v) => to_py_decimal(v, py)?,
129139
BorrowedValue::Blob(v) => v.into_py(py),
130140
BorrowedValue::MediumBlob(_) => todo!(),
131141
};
132142
vec.push(val);
133143
}
134-
PyTuple::new(py, vec).to_object(py)
144+
Ok(PyTuple::new(py, vec).to_object(py))
135145
}
136146

137-
pub fn get_row_of_block(py: Python, block: &RawBlock, index: usize) -> Option<PyObject> {
147+
pub fn get_row_of_block(py: Python, block: &RawBlock, index: usize) -> PyResult<Option<PyObject>> {
138148
if block.nrows() > index {
139-
Some(unsafe { get_row_of_block_unchecked(py, block, index) })
149+
Ok(Some(unsafe {
150+
get_row_of_block_unchecked(py, block, index)?
151+
}))
140152
} else {
141-
None
153+
Ok(None)
142154
}
143155
}
144156

145157
pub fn get_slice_of_block(
146158
py: Python,
147159
block: &RawBlock,
148160
range: Range<usize>,
149-
) -> (Vec<PyObject>, Option<usize>) {
161+
) -> PyResult<(Vec<PyObject>, Option<usize>)> {
150162
debug_assert!(range.start < block.nrows());
151163
let start = range.start;
152164
let end = range.end;
@@ -159,14 +171,14 @@ pub fn get_slice_of_block(
159171
let slices = range
160172
.into_iter()
161173
.map(|index| unsafe { get_row_of_block_unchecked(py, block, index) })
162-
.collect();
174+
.collect::<PyResult<Vec<_>>>()?;
163175

164-
(slices, remain)
176+
Ok((slices, remain))
165177
}
166178

167-
pub fn get_all_of_block(py: Python, block: &RawBlock) -> Vec<PyObject> {
179+
pub fn get_all_of_block(py: Python, block: &RawBlock) -> PyResult<Vec<PyObject>> {
168180
(0..block.nrows())
169181
.into_iter()
170182
.map(|index| unsafe { get_row_of_block_unchecked(py, block, index) })
171-
.collect()
183+
.collect::<PyResult<Vec<_>>>()
172184
}

taos-ws-py/src/consumer.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ impl MessageBlock {
354354
self.block.ncols()
355355
}
356356

357-
pub fn fetchall(&self) -> Vec<PyObject> {
357+
pub fn fetchall(&self) -> PyResult<Vec<PyObject>> {
358358
Python::with_gil(|py| get_all_of_block(py, &self.block))
359359
}
360360

@@ -379,7 +379,7 @@ impl MessageBlockIter {
379379
Ok(None)
380380
} else {
381381
Python::with_gil(|py| {
382-
let values = unsafe { get_row_of_block_unchecked(py, &slf.block, slf.index) };
382+
let values = unsafe { get_row_of_block_unchecked(py, &slf.block, slf.index)? };
383383
slf.index += 1;
384384
Ok(Some(values))
385385
})

taos-ws-py/src/cursor.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -279,14 +279,14 @@ impl Cursor {
279279
pub fn fetchone(&mut self) -> PyResult<Option<PyObject>> {
280280
self.assert_block()?;
281281

282-
Ok(Python::with_gil(|py| -> Option<PyObject> {
282+
Python::with_gil(|py| -> PyResult<Option<PyObject>> {
283283
if let Some(block) = self.block.as_ref() {
284-
let row = get_row_of_block(py, block, self.row_in_block).unwrap();
284+
let row = get_row_of_block(py, block, self.row_in_block)?;
285285
self.row_in_block += 1;
286-
return Some(row);
286+
return Ok(row);
287287
}
288-
None
289-
}))
288+
Ok(None)
289+
})
290290
}
291291

292292
/// PEP249 void method
@@ -299,7 +299,7 @@ impl Cursor {
299299
let mut all = Vec::new();
300300
loop {
301301
if let Some(block) = self.block.take() {
302-
let (slice, remain) = get_slice_of_block(py, &block, range.clone());
302+
let (slice, remain) = get_slice_of_block(py, &block, range.clone())?;
303303
all.extend(slice);
304304
if remain.is_none() {
305305
self.block = Some(block);
@@ -323,7 +323,7 @@ impl Cursor {
323323
self.row_in_block = 0;
324324
if let Some(block) = self.block.take() {
325325
self.row_count += block.nrows();
326-
return Ok(Some(Python::with_gil(|py| get_all_of_block(py, &block))));
326+
return Ok(Some(Python::with_gil(|py| get_all_of_block(py, &block))?));
327327
} else {
328328
return Ok(None);
329329
}

0 commit comments

Comments
 (0)