06-rust.mdx 20.4 KB
Newer Older
1 2
---
title: TDengine Rust Connector
D
danielclow 已提交
3 4 5
sidebar_label: Rust
description: This document describes the TDengine Rust connector.
toc_max_heading_level: 4
6 7 8 9 10
---

import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

G
gccgdb1234 已提交
11
import Preparition from "./_preparation.mdx"
12
import RustInsert from "../../07-develop/03-insert-data/_rust_sql.mdx"
13
import RustBind from "../../07-develop/03-insert-data/_rust_stmt.mdx"
A
Adam Ji 已提交
14
import RustSml from "../../07-develop/03-insert-data/_rust_schemaless.mdx"
15 16
import RustQuery from "../../07-develop/04-query-data/_rust.mdx"

D
danielclow 已提交
17
[![Crates.io](https://img.shields.io/crates/v/taos)](https://crates.io/crates/taos) ![Crates.io](https://img.shields.io/crates/d/taos) [![docs.rs](https://img.shields.io/docsrs/taos)](https://docs.rs/taos)
18

D
danielclow 已提交
19
`taos` is the official Rust connector for TDengine. Rust developers can develop applications to access the TDengine instance data.
20

D
danielclow 已提交
21 22 23
`taos` provides two ways to establish connections. One is the **Native Connection**, which connects to TDengine instances via the TDengine client driver (taosc). The other is the **WebSocket connection**, which connects to TDengine instances via the WebSocket interface provided by taosAdapter. You can specify a connection type with Cargo features. By default, both types are supported. The Websocket connection can be used on any platform. The native connection can be used on any platform that the TDengine Client supports.

The source code for the Rust connectors is located on [GitHub](https://github.com/taosdata/taos-connector-rust).
24 25 26

## Supported platforms

D
danielclow 已提交
27 28
Native connections are supported on the same platforms as the TDengine client driver.
Websocket connections are supported on all platforms that can run Go.
29

A
Adam Ji 已提交
30 31 32 33
## Version history

| connector-rust version |  TDengine version |                   major features                    |
| :----------------: | :--------------: | :--------------------------------------------------: |
A
Adam Ji 已提交
34
|       v0.8.12       |      3.0.5.0 or later    | TMQ: Get consuming progress and seek offset to consume. |
A
Adam Ji 已提交
35 36 37
|       v0.8.0       |      3.0.4.0     | Support schemaless insert. |
|       v0.7.6       |      3.0.3.0     | Support req_id in query. |
|       v0.6.0       |      3.0.0.0     | Base features. |
38

39
The Rust Connector is still under rapid development and is not guaranteed to be backward compatible before 1.0. We recommend using TDengine version 3.0 or higher to avoid known issues.
40

A
Adam Ji 已提交
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
## Handling exceptions

After the error is reported, the specific information of the error can be obtained:

```rust
match conn.exec(sql) {
    Ok(_) => {
        Ok(())
    }
    Err(e) => {
        eprintln!("ERROR: {:?}", e);
        Err(e)
    }
}
```

## TDengine DataType vs. Rust DataType

TDengine currently supports timestamp, number, character, Boolean type, and the corresponding type conversion with Rust is as follows:

| TDengine DataType | Rust DataType     |
| ----------------- | ----------------- |
| TIMESTAMP         | Timestamp         |
| INT               | i32               |
| BIGINT            | i64               |
| FLOAT             | f32               |
| DOUBLE            | f64               |
| SMALLINT          | i16               |
| TINYINT           | i8                |
| BOOL              | bool              |
| BINARY            | Vec<u8\>          |
| NCHAR             | String            |
| JSON              | serde_json::Value |

Note: Only TAG supports JSON types

## Installation Steps
78

D
danielclow 已提交
79
### Pre-installation preparation
80

81 82 83
* Install the Rust development toolchain
* If using the native connection, please install the TDengine client driver. Please refer to [install client driver](/reference/connector#install-client-driver)

A
Adam Ji 已提交
84
### Install the connectors
85

D
danielclow 已提交
86
Depending on the connection method, add the [taos][taos] dependency in your Rust project as follows:
87

88
<Tabs defaultValue="default">
D
danielclow 已提交
89
<TabItem value="default" label="Support Both">
90

D
danielclow 已提交
91
In `cargo.toml`, add [taos][taos]:
92

D
dingbo 已提交
93
```toml
94 95
[dependencies]
# use default feature
96
taos = "*"
97 98
```

D
dingbo 已提交
99
</TabItem>
100

101
<TabItem value="rest" label="Websocket only">
D
danielclow 已提交
102

103
In `cargo.toml`, add [taos][taos] and enable the ws feature:
104 105 106

```toml
[dependencies]
107
taos = { version = "*", default-features = false, features = ["ws"] }
108 109 110 111
```

</TabItem>

112 113 114
<TabItem value="native" label="native connection only">

In `cargo.toml`, add [taos][taos] and enable the native feature:
115 116 117

```toml
[dependencies]
118
taos = { version = "*", default-features = false, features = ["native"] }
119 120
```

121
</TabItem>
122

123 124
</Tabs>

D
danielclow 已提交
125
## Establishing a connection
126

D
danielclow 已提交
127
[TaosBuilder] creates a connection constructor through the DSN connection description string.
128 129

```rust
130
let builder = TaosBuilder::from_dsn("taos://")?;
131 132
```

D
danielclow 已提交
133
You can now use this object to create the connection.
134 135

```rust
136
let conn = builder.build()?;
137 138 139 140 141
```

The connection object can create more than one.

```rust
142 143 144 145
let conn1 = builder.build()?;
let conn2 = builder.build()?;
```

D
danielclow 已提交
146
The structure of the DSN description string is as follows:
147 148 149 150 151

```text
<driver>[+<protocol>]://[[<username>:<password>@]<host>:<port>][/<database>][?<p1>=<v1>[&<p2>=<v2>]]
|------|------------|---|-----------|-----------|------|------|------------|-----------------------|
|driver|   protocol |   | username  | password  | host | port |  database  |  params               |
152 153
```

D
danielclow 已提交
154 155 156 157 158 159 160 161 162 163
The parameters are described as follows:

- **driver**: Specify a driver name so that the connector can choose which method to use to establish the connection. Supported driver names are as follows:
  - **taos**: Table names use the TDengine connector driver.
  - **tmq**: Use the TMQ to subscribe to data.
  - **http/ws**: Use Websocket to establish connections.
  - **https/wss**: Use Websocket to establish connections, and enable SSL/TLS.
- **protocol**: Specify which connection method to use. For example, `taos+ws://localhost:6041` uses Websocket to establish connections.
- **username/password**: Username and password used to create connections.
- **host/port**: Specifies the server and port to establish a connection. If you do not specify a hostname or port, native connections default to `localhost:6030` and Websocket connections default to `localhost:6041`.
164
- **database**: Specify the default database to connect to. It's optional.
165
- **params**: Optional parameters.
D
danielclow 已提交
166 167

A sample DSN description string is as follows:
168 169 170 171 172

```text
taos+ws://localhost:6041/test
```

D
danielclow 已提交
173
This indicates that the Websocket connection method is used on port 6041 to connect to the server localhost and use the database `test` by default.
174

D
danielclow 已提交
175
You can create DSNs to connect to servers in your environment.
176 177

```rust
D
danielclow 已提交
178
use taos::*;
179

180 181 182 183 184
// use native protocol.
let builder = TaosBuilder::from_dsn("taos://localhost:6030")?;
let conn1 = builder.build();

//  use websocket protocol.
A
Adam Ji 已提交
185 186
let builder2 = TaosBuilder::from_dsn("taos+ws://localhost:6041")?;
let conn2 = builder2.build();
187 188
```

D
danielclow 已提交
189
After the connection is established, you can perform operations on your database.
190 191

```rust
192 193 194 195 196 197 198 199 200 201 202 203
async fn demo(taos: &Taos, db: &str) -> Result<(), Error> {
    // prepare database
    taos.exec_many([
        format!("DROP DATABASE IF EXISTS `{db}`"),
        format!("CREATE DATABASE `{db}`"),
        format!("USE `{db}`"),
    ])
    .await?;

    let inserted = taos.exec_many([
        // create super table
        "CREATE TABLE `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) \
204
         TAGS (`groupid` INT, `location` BINARY(24))",
205
        // create child table
206
        "CREATE TABLE `d0` USING `meters` TAGS(0, 'California.LosAngles')",
207 208 209 210 211
        // insert into child table
        "INSERT INTO `d0` values(now - 10s, 10, 116, 0.32)",
        // insert with NULL values
        "INSERT INTO `d0` values(now - 8s, NULL, NULL, NULL)",
        // insert and automatically create table with tags if not exists
212
        "INSERT INTO `d1` USING `meters` TAGS(1, 'California.SanFrancisco') values(now - 9s, 10.1, 119, 0.33)",
213 214 215 216 217 218 219 220 221
        // insert many records in a single sql
        "INSERT INTO `d1` values (now-8s, 10, 120, 0.33) (now - 6s, 10, 119, 0.34) (now - 4s, 11.2, 118, 0.322)",
    ]).await?;

    assert_eq!(inserted, 6);
    let mut result = taos.query("select * from `meters`").await?;

    for field in result.fields() {
        println!("got field: {}", field.name());
222
    }
223 224

    let values = result.
225 226 227
}
```

D
danielclow 已提交
228
There are two ways to query data: Using built-in types or the [serde](https://serde.rs) deserialization framework.
229

230 231 232 233 234 235 236 237
```rust
    // Query option 1, use rows stream.
    let mut rows = result.rows();
    while let Some(row) = rows.try_next().await? {
        for (name, value) in row {
            println!("got value of {}: {}", name, value);
        }
    }
238

239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
    // Query options 2, use deserialization with serde.
    #[derive(Debug, serde::Deserialize)]
    #[allow(dead_code)]
    struct Record {
        // deserialize timestamp to chrono::DateTime<Local>
        ts: DateTime<Local>,
        // float to f32
        current: Option<f32>,
        // int to i32
        voltage: Option<i32>,
        phase: Option<f32>,
        groupid: i32,
        // binary/varchar to String
        location: String,
    }
254

255 256 257 258 259 260
    let records: Vec<Record> = taos
        .query("select * from `meters`")
        .await?
        .deserialize()
        .try_collect()
        .await?;
261

262 263 264
    dbg!(records);
    Ok(())
```
265

266
## Usage examples
267

A
Adam Ji 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
### Create database and tables

```rust
use taos::*;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let dsn = "taos://localhost:6030";
    let builder = TaosBuilder::from_dsn(dsn)?;

    let taos = builder.build()?;

    let db = "query";

    // create database
    taos.exec_many([
        format!("DROP DATABASE IF EXISTS `{db}`"),
        format!("CREATE DATABASE `{db}`"),
        format!("USE `{db}`"),
    ])
    .await?;

    // create table
    taos.exec_many([
        // create super table
        "CREATE TABLE `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) \
         TAGS (`groupid` INT, `location` BINARY(16))",
        // create child table
        "CREATE TABLE `d0` USING `meters` TAGS(0, 'Los Angles')",
    ]).await?;
}
```
300

A
Adam Ji 已提交
301 302
> The query is consistent with operating a relational database. When using subscripts to get the contents of the returned fields, you have to start from 1. However, we recommend using the field names to get the values of the fields in the result set.

A
Adam Ji 已提交
303
### Insert data
304

305
<RustInsert />
306

A
Adam Ji 已提交
307 308 309 310 311 312 313 314 315 316 317 318 319
### Query data

<RustQuery />

### execute SQL with req_id

This req_id can be used to request link tracing.

```rust
let rs = taos.query_with_req_id("select * from stable where tag1 is null", 1)?;
```

### Writing data via parameter binding
320

A
Adam Ji 已提交
321 322
TDengine has significantly improved the bind APIs to support data writing (INSERT) scenarios. Writing data in this way avoids the resource consumption of SQL syntax parsing, resulting in significant write performance improvements in many cases.

A
Adam Ji 已提交
323 324
Parameter binding details see [API Reference](#stmt-api)

325
<RustBind />
326

A
Adam Ji 已提交
327
### Schemaless Writing
A
Adam Ji 已提交
328

A
Adam Ji 已提交
329 330
TDengine supports schemaless writing. It is compatible with InfluxDB's Line Protocol, OpenTSDB's telnet line protocol, and OpenTSDB's JSON format protocol. For more information, see [Schemaless Writing](../../schemaless).

A
Adam Ji 已提交
331 332
<RustSml />

A
Adam Ji 已提交
333
### Schemaless with req_id
334

A
Adam Ji 已提交
335
This req_id can be used to request link tracing.
336

A
Adam Ji 已提交
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418
```rust
let sml_data = SmlDataBuilder::default()
    .protocol(SchemalessProtocol::Line)
    .data(data)
    .req_id(100u64)
    .build()?;

client.put(&sml_data)?
```

### Data Subscription

TDengine starts subscriptions through [TMQ](../../../taos-sql/tmq/).

#### Create a Topic

```rust
taos.exec_many([
    // create topic for subscription
    format!("CREATE TOPIC tmq_meters with META AS DATABASE {db}")
])
.await?;
```

#### Create a Consumer

You create a TMQ connector by using a DSN.

```rust
let tmq = TmqBuilder::from_dsn("taos://localhost:6030/?group.id=test")?;
```

Create a consumer:

```rust
let mut consumer = tmq.build()?;
```

#### Subscribe to consume data

A single consumer can subscribe to one or more topics.

```rust
consumer.subscribe(["tmq_meters"]).await?;
```

The TMQ is of [futures::Stream](https://docs.rs/futures/latest/futures/stream/index.html) type. You can use the corresponding API to consume each message in the queue and then use `.commit` to mark them as consumed.

```rust
{
    let mut stream = consumer.stream();

    while let Some((offset, message)) = stream.try_next().await? {
        // get information from offset

        // the topic
        let topic = offset.topic();
        // the vgroup id, like partition id in kafka.
        let vgroup_id = offset.vgroup_id();
        println!("* in vgroup id {vgroup_id} of topic {topic}\n");

        if let Some(data) = message.into_data() {
            while let Some(block) = data.fetch_raw_block().await? {
                // one block for one table, get table name if needed
                let name = block.table_name();
                let records: Vec<Record> = block.deserialize().try_collect()?;
                println!(
                    "** table: {}, got {} records: {:#?}\n",
                    name.unwrap(),
                    records.len(),
                    records
                );
            }
        }
        consumer.commit(offset).await?;
    }
}
```

Get assignments:

Version requirements connector-rust >= v0.8.8, TDengine >= 3.0.5.0
419

A
Adam Ji 已提交
420 421 422 423 424 425 426
```rust
let assignments = consumer.assignments().await.unwrap();
```

#### Assignment subscription Offset

Seek offset:
427

A
Adam Ji 已提交
428
Version requirements connector-rust >= v0.8.8, TDengine >= 3.0.5.0
429 430

```rust
A
Adam Ji 已提交
431
consumer.offset_seek(topic, vgroup_id, offset).await;
432 433
```

A
Adam Ji 已提交
434
#### Close subscriptions
435 436

```rust
A
Adam Ji 已提交
437
consumer.unsubscribe().await;
438 439
```

A
Adam Ji 已提交
440 441 442 443 444 445 446 447 448 449 450 451 452
The following parameters can be configured for the TMQ DSN. Only `group.id` is mandatory.

- `group.id`: Within a consumer group, load balancing is implemented by consuming messages on an at-least-once basis.
- `client.id`: Subscriber client ID.
- `auto.offset.reset`: Initial point of subscription. *earliest* subscribes from the beginning, and *latest* subscribes from the newest message. The default is earliest. Note: This parameter is set per consumer group.
- `enable.auto.commit`: Automatically commits. This can be enabled when data consistency is not essential.
- `auto.commit.interval.ms`: Interval for automatic commits.

#### Full Sample Code
  
For more information, see [GitHub sample file](https://github.com/taosdata/TDengine/blob/3.0/docs/examples/rust/nativeexample/examples/subscribe_demo.rs).

### Use with connection pool
453

D
danielclow 已提交
454
In complex applications, we recommend enabling connection pools. [taos] implements connection pools based on [r2d2].
455

D
danielclow 已提交
456
As follows, a connection pool with default parameters can be generated.
457 458

```rust
459
let pool = TaosBuilder::from_dsn(dsn)?.pool()?;
460 461
```

D
danielclow 已提交
462
You can set the same connection pool parameters using the connection pool's constructor.
463 464

```rust
465 466 467 468 469 470 471 472 473
let dsn = "taos://localhost:6030";

let opts = PoolBuilder::new()
    .max_size(5000) // max connections
    .max_lifetime(Some(Duration::from_secs(60 * 60))) // lifetime of each connection
    .min_idle(Some(1000)) // minimal idle connections
    .connection_timeout(Duration::from_secs(2));

let pool = TaosBuilder::from_dsn(dsn)?.with_pool_builder(opts)?;
474 475
```

D
danielclow 已提交
476
In the application code, use `pool.get()? ` to get a connection object [Taos].
477 478

```rust
D
danielclow 已提交
479
let taos = pool.get()?;
480 481
```

A
Adam Ji 已提交
482 483 484 485 486 487 488 489 490 491 492
### More sample programs

The source code of the sample application is under `TDengine/examples/rust` :

[rust example](https://github.com/taosdata/TDengine/tree/3.0/examples/rust)

## Frequently Asked Questions

For additional troubleshooting, see [FAQ](../../../train-faq/faq).

## API Reference
493

D
danielclow 已提交
494
The [Taos][struct.Taos] object provides an API to perform operations on multiple databases.
495

D
danielclow 已提交
496
1. `exec`: Execute some non-query SQL statements, such as `CREATE`, `ALTER`, `INSERT`, etc.
497 498 499 500 501

    ```rust
    let affected_rows = taos.exec("INSERT INTO tb1 VALUES(now, NULL)").await?;
    ```

D
danielclow 已提交
502
2. `exec_many`: Run multiple SQL statements simultaneously or in order.
503 504

    ```rust
505 506 507 508 509
    taos.exec_many([
        "CREATE DATABASE test",
        "USE test",
        "CREATE TABLE `tb1` (`ts` TIMESTAMP, `val` INT)",
    ]).await?;
510 511
    ```

D
danielclow 已提交
512
3. `query`: Run a query statement and return a [ResultSet] object.
513 514

    ```rust
D
danielclow 已提交
515
    let mut q = taos.query("select * from log.logs").await?;
516 517
    ```

D
danielclow 已提交
518
    The [ResultSet] object stores query result data and the names, types, and lengths of returned columns
519

D
danielclow 已提交
520
    You can obtain column information by using [.fields()].
521

D
dingbo 已提交
522
    ```rust
523
    let cols = q.fields();
524
    for col in cols {
525
        println!("name: {}, type: {:?} , bytes: {}", col.name(), col.ty(), col.bytes());
526 527 528
    }
    ```

D
danielclow 已提交
529
    It fetches data line by line.
530 531

    ```rust
532 533 534 535 536 537 538 539
    let mut rows = result.rows();
    let mut nrows = 0;
    while let Some(row) = rows.try_next().await? {
        for (col, (name, value)) in row.enumerate() {
            println!(
                "[{}] got value in col {} (named `{:>8}`): {}",
                nrows, col, name, value
            );
540
        }
541 542 543 544
        nrows += 1;
    }
    ```

D
danielclow 已提交
545
    Or use the [serde](https://serde.rs) deserialization framework.
546 547 548 549 550 551 552 553 554 555 556 557 558 559

    ```rust
    #[derive(Debug, Deserialize)]
    struct Record {
        // deserialize timestamp to chrono::DateTime<Local>
        ts: DateTime<Local>,
        // float to f32
        current: Option<f32>,
        // int to i32
        voltage: Option<i32>,
        phase: Option<f32>,
        groupid: i32,
        // binary/varchar to String
        location: String,
560
    }
561 562 563 564 565 566 567

    let records: Vec<Record> = taos
        .query("select * from `meters`")
        .await?
        .deserialize()
        .try_collect()
        .await?;
568 569 570 571
    ```

Note that Rust asynchronous functions and an asynchronous runtime are required.

D
danielclow 已提交
572
[Taos][struct.Taos] provides Rust methods for some SQL statements to reduce the number of `format!`s.
573 574 575 576 577

- `.describe(table: &str)`: Executes `DESCRIBE` and returns a Rust data structure.
- `.create_database(database: &str)`: Executes the `CREATE DATABASE` statement.
- `.use_database(database: &str)`: Executes the `USE` statement.

A
Adam Ji 已提交
578
In addition, this structure is also the entry point for Parameter Binding and Line Protocol Interface. Please refer to the specific API descriptions for usage.
D
danielclow 已提交
579

A
Adam Ji 已提交
580 581
<p>
<a id="stmt-api" style={{color:'#141414'}}>
A
Adam Ji 已提交
582
Bind Interface
A
Adam Ji 已提交
583 584
</a>
</p>
585

D
danielclow 已提交
586
Similar to the C interface, Rust provides the bind interface's wrapping. First, the [Taos][struct.taos] object creates a parameter binding object [Stmt] for an SQL statement.
587 588

```rust
589 590
let mut stmt = Stmt::init(&taos).await?;
stmt.prepare("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)")?;
591 592 593 594
```

The bind object provides a set of interfaces for implementing parameter binding.

A
Adam Ji 已提交
595
`.set_tbname(name)`
596 597 598

To bind table names.

599 600 601 602 603
```rust
let mut stmt = taos.stmt("insert into ? values(? ,?)")?;
stmt.set_tbname("d0")?;
```

A
Adam Ji 已提交
604
`.set_tags(&[tag])`
605

D
danielclow 已提交
606
Bind sub-table table names and tag values when the SQL statement uses a super table.
607 608

```rust
609 610
let mut stmt = taos.stmt("insert into ? using stb0 tags(?) values(? ,?)")?;
stmt.set_tbname("d0")?;
D
danielclow 已提交
611
stmt.set_tags(&[Value::VarChar("taos".to_string())])?;
612 613
```

A
Adam Ji 已提交
614
`.bind(&[column])`
615

D
danielclow 已提交
616
Bind value types. Use the [ColumnView] structure to create and bind the required types.
617 618

```rust
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
let params = vec![
    ColumnView::from_millis_timestamp(vec![164000000000]),
    ColumnView::from_bools(vec![true]),
    ColumnView::from_tiny_ints(vec![i8::MAX]),
    ColumnView::from_small_ints(vec![i16::MAX]),
    ColumnView::from_ints(vec![i32::MAX]),
    ColumnView::from_big_ints(vec![i64::MAX]),
    ColumnView::from_unsigned_tiny_ints(vec![u8::MAX]),
    ColumnView::from_unsigned_small_ints(vec![u16::MAX]),
    ColumnView::from_unsigned_ints(vec![u32::MAX]),
    ColumnView::from_unsigned_big_ints(vec![u64::MAX]),
    ColumnView::from_floats(vec![f32::MAX]),
    ColumnView::from_doubles(vec![f64::MAX]),
    ColumnView::from_varchar(vec!["ABC"]),
    ColumnView::from_nchar(vec!["涛思数据"]),
];
let rows = stmt.bind(&params)?.add_batch()?.execute()?;
636 637
```

A
Adam Ji 已提交
638
`.execute()`
639

D
danielclow 已提交
640
Execute SQL. [Stmt] objects can be reused, re-binded, and executed after execution. Before execution, ensure that all data has been added to the queue with `.add_batch`.
641 642

```rust
D
danielclow 已提交
643
stmt.execute()?;
644 645

// next bind cycle.
D
danielclow 已提交
646 647 648
//stmt.set_tbname()?;
//stmt.bind()?;
//stmt.execute()?;
649 650
```

D
danielclow 已提交
651
For a working example, see [GitHub](https://github.com/taosdata/taos-connector-rust/blob/main/examples/bind.rs).
652 653


D
danielclow 已提交
654
For information about other structure APIs, see the [Rust documentation](https://docs.rs/taos).
655

D
danielclow 已提交
656
[taos]: https://github.com/taosdata/rust-connector-taos
657
[r2d2]: https://crates.io/crates/r2d2
D
danielclow 已提交
658 659 660 661
[TaosBuilder]: https://docs.rs/taos/latest/taos/struct.TaosBuilder.html
[TaosCfg]: https://docs.rs/taos/latest/taos/struct.TaosCfg.html
[struct.Taos]: https://docs.rs/taos/latest/taos/struct.Taos.html
[Stmt]: https://docs.rs/taos/latest/taos/struct.Stmt.html