From cbf666b529fd80ea72a91ee3fd17ff2c454f45ba Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Thu, 1 Aug 2024 21:15:53 +0800 Subject: [PATCH 1/7] mod tmq example --- docs/zh/08-develop/07-tmq.md | 66 +--- .../com/taosdata/example/AbsConsumerLoop.java | 2 +- .../taosdata/example/AbsConsumerLoopFull.java | 142 ------- .../taosdata/example/AbsWsConsumerLoop.java | 144 ------- .../taosdata/example/ConsumerLoopFull.java | 357 +++++++++++++++++ .../example/ParameterBindingBasicDemo.java | 44 ++- .../example/ParameterBindingBatchDemo.java | 83 ---- .../taosdata/example/WsConsumerLoopFull.java | 358 ++++++++++++++++++ 8 files changed, 764 insertions(+), 432 deletions(-) delete mode 100644 examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoopFull.java delete mode 100644 examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java create mode 100644 examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java delete mode 100644 examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBatchDemo.java create mode 100644 examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java diff --git a/docs/zh/08-develop/07-tmq.md b/docs/zh/08-develop/07-tmq.md index 16a538757f..1d5b59307e 100644 --- a/docs/zh/08-develop/07-tmq.md +++ b/docs/zh/08-develop/07-tmq.md @@ -85,7 +85,7 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java:create_consumer}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:create_consumer}} ``` @@ -135,7 +135,7 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java:create_consumer}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java:create_consumer}} ``` @@ -180,7 +180,7 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java:poll_data_code_piece}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:poll_data_code_piece}} ``` - `subscribe` 方法的参数含义为:订阅的主题列表(即名称),支持同时订阅多个主题。 @@ -273,33 +273,7 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 ```java - -// 获取当前消费者分配的 TopicPartition 集合 -Set assignment() throws SQLException; - -// 获取指定分区的当前偏移量 -long position(TopicPartition partition) throws SQLException; -// 获取指定主题的所有分区的当前偏移量 -Map position(String topic) throws SQLException; -// 获取指定主题的所有分区的起始偏移量 -Map beginningOffsets(String topic) throws SQLException; -// 获取指定主题的所有分区的最新偏移量 -Map endOffsets(String topic) throws SQLException; -// 获取指定分区集合中的已提交偏移量 -Map committed(Set partitions) throws SQLException; - -// 设置指定分区的偏移量 -void seek(TopicPartition partition, long offset) throws SQLException; -// 将指定分区集合的偏移量设置为最开始 -void seekToBeginning(Collection partitions) throws SQLException; -// 将指定分区集合的偏移量设置为最新 -void seekToEnd(Collection partitions) throws SQLException; -``` - -示例代码: - -```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerOffsetSeek.java:consumer_seek}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:consumer_seek}} ``` @@ -344,7 +318,6 @@ void seekToEnd(Collection partitions) throws SQLException; - 同 Websocket 代码样例。 @@ -389,22 +362,9 @@ void seekToEnd(Collection partitions) throws SQLException; -```java -// 同步提交当前消费者的偏移量 -void commitSync() throws SQLException; -// 同步提交指定的偏移量 -void commitSync(Map offsets) throws SQLException; - -// 异步提交仅在 native 连接下有效 -// 异步提交当前消费者的偏移量,需要提供回调以处理可能的提交结果 -void commitAsync(OffsetCommitCallback callback) throws SQLException; -// 异步提交指定的偏移量,需要提供回调以处理可能的提交结果 -void commitAsync(Map offsets, OffsetCommitCallback callback) throws SQLException; -``` - ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java:commit_code_piece}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:commit_code_piece}} ``` @@ -501,7 +461,7 @@ void commitAsync(Map offsets, OffsetCommitCal ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java:unsubscribe_data_code_piece}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:unsubscribe_data_code_piece}} ``` @@ -593,12 +553,14 @@ void commitAsync(Map offsets, OffsetCommitCal ### Websocket 连接 +
+完整 Websocket 连接代码示例 ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java:consumer_demo}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java:consumer_demo}} ``` **注意**:这里的 value.deserializer 配置参数值应该根据测试环境的包路径做相应的调整。 -其余代码请参考: [JDBC example](https://github.com/taosdata/TDengine/tree/3.0/examples/JDBC/JDBCDemo) +
@@ -641,12 +603,16 @@ void commitAsync(Map offsets, OffsetCommitCal ### 原生连接 +
+完整原生连接代码示例 ```java -{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoopFull.java:consumer_demo}} +{{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java:consumer_demo}} ``` **注意**:这里的 value.deserializer 配置参数值应该根据测试环境的包路径做相应的调整。 -其余代码请参考: [JDBC example](https://github.com/taosdata/TDengine/tree/3.0/examples/JDBC/JDBCDemo) +
+ +
diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java index 90e6a950cd..f7570c742a 100644 --- a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java +++ b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoop.java @@ -32,7 +32,7 @@ config.setProperty("msg.with.table.name", "true"); config.setProperty("enable.auto.commit", "true"); config.setProperty("auto.commit.interval.ms", "1000"); config.setProperty("group.id", "group1"); -config.setProperty("client.id", "1"); +config.setProperty("client.id", "client1"); config.setProperty("value.deserializer", "com.taosdata.example.AbsConsumerLoop$ResultDeserializer"); config.setProperty("value.deserializer.encoding", "UTF-8"); try { diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoopFull.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoopFull.java deleted file mode 100644 index bd8f1799f6..0000000000 --- a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsConsumerLoopFull.java +++ /dev/null @@ -1,142 +0,0 @@ -package com.taosdata.example; - -import com.taosdata.jdbc.tmq.ConsumerRecord; -import com.taosdata.jdbc.tmq.ConsumerRecords; -import com.taosdata.jdbc.tmq.ReferenceDeserializer; -import com.taosdata.jdbc.tmq.TaosConsumer; - -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - -// ANCHOR: consumer_demo -public abstract class AbsConsumerLoopFull { - private final TaosConsumer consumer; - private final List topics; - private final AtomicBoolean shutdown; - private final CountDownLatch shutdownLatch; - - public AbsConsumerLoopFull() throws SQLException { - - Properties config = new Properties(); - config.setProperty("td.connect.type", "jni"); - config.setProperty("bootstrap.servers", "localhost:6030"); - config.setProperty("auto.offset.reset", "latest"); - config.setProperty("msg.with.table.name", "true"); - config.setProperty("enable.auto.commit", "true"); - config.setProperty("auto.commit.interval.ms", "1000"); - config.setProperty("group.id", "group1"); - config.setProperty("client.id", "1"); - config.setProperty("value.deserializer", "com.taosdata.example.AbsConsumerLoop$ResultDeserializer"); - config.setProperty("value.deserializer.encoding", "UTF-8"); - - try { - this.consumer = new TaosConsumer<>(config); - } catch (SQLException ex) { - // handle any errors, please refer to the JDBC specifications for detailed exceptions info - System.out.println("Failed to create jni consumer, host : " + config.getProperty("bootstrap.servers") + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); - throw new SQLException("Failed to create consumer", ex); - } - - this.topics = Collections.singletonList("topic_meters"); - this.shutdown = new AtomicBoolean(false); - this.shutdownLatch = new CountDownLatch(1); - } - - public abstract void process(ResultBean result); - - public void pollData() throws SQLException { - try { - // subscribe to the topics - consumer.subscribe(topics); - while (!shutdown.get()) { - // poll data - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - for (ConsumerRecord record : records) { - ResultBean bean = record.value(); - // process the data here - process(bean); - } - } - // unsubscribe the topics - consumer.unsubscribe(); - } finally { - // close the consumer - consumer.close(); - shutdownLatch.countDown(); - } - } - - public void shutdown() throws InterruptedException { - shutdown.set(true); - shutdownLatch.await(); - } - - public static class ResultDeserializer extends ReferenceDeserializer { - - } - - // use this class to define the data structure of the result record - public static class ResultBean { - private Timestamp ts; - private double current; - private int voltage; - private double phase; - private int groupid; - private String location; - - public Timestamp getTs() { - return ts; - } - - public void setTs(Timestamp ts) { - this.ts = ts; - } - - public double getCurrent() { - return current; - } - - public void setCurrent(double current) { - this.current = current; - } - - public int getVoltage() { - return voltage; - } - - public void setVoltage(int voltage) { - this.voltage = voltage; - } - - public double getPhase() { - return phase; - } - - public void setPhase(double phase) { - this.phase = phase; - } - - public int getGroupid() { - return groupid; - } - - public void setGroupid(int groupid) { - this.groupid = groupid; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - } -} -// ANCHOR_END: consumer_demo diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java deleted file mode 100644 index 60466629f6..0000000000 --- a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/AbsWsConsumerLoop.java +++ /dev/null @@ -1,144 +0,0 @@ -package com.taosdata.example; - -import com.taosdata.jdbc.tmq.ConsumerRecord; -import com.taosdata.jdbc.tmq.ConsumerRecords; -import com.taosdata.jdbc.tmq.ReferenceDeserializer; -import com.taosdata.jdbc.tmq.TaosConsumer; - -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.Duration; -import java.util.Collections; -import java.util.List; -import java.util.Properties; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.atomic.AtomicBoolean; - -// ANCHOR: consumer_demo -public abstract class AbsWsConsumerLoop { - private final TaosConsumer consumer; - private final List topics; - private final AtomicBoolean shutdown; - private final CountDownLatch shutdownLatch; - - public AbsWsConsumerLoop() throws SQLException { -// ANCHOR: create_consumer -Properties config = new Properties(); -config.setProperty("td.connect.type", "ws"); -config.setProperty("bootstrap.servers", "localhost:6041"); -config.setProperty("auto.offset.reset", "latest"); -config.setProperty("msg.with.table.name", "true"); -config.setProperty("enable.auto.commit", "true"); -config.setProperty("auto.commit.interval.ms", "1000"); -config.setProperty("group.id", "group1"); -config.setProperty("client.id", "client1"); -config.setProperty("value.deserializer", "com.taosdata.example.AbsConsumerLoopWs$ResultDeserializer"); -config.setProperty("value.deserializer.encoding", "UTF-8"); - -try { - this.consumer = new TaosConsumer<>(config); -} catch (SQLException ex) { - // handle any errors, please refer to the JDBC specifications for detailed exceptions info - System.out.println("Failed to create ws consumer with " + config.getProperty("bootstrap.servers") + " ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); - throw new SQLException("Failed to create consumer", ex); -} -// ANCHOR_END: create_consumer - - this.topics = Collections.singletonList("topic_meters"); - this.shutdown = new AtomicBoolean(false); - this.shutdownLatch = new CountDownLatch(1); - } - - public abstract void process(ResultBean result); - - public void pollData() throws SQLException { - try { - // Subscribe to the topic - consumer.subscribe(topics); - - while (!shutdown.get()) { - // poll data - ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); - for (ConsumerRecord record : records) { - ResultBean bean = record.value(); - // process data here - process(bean); - } - } - // unsubscribe the topics - consumer.unsubscribe(); - } finally { - // close the consumer - consumer.close(); - shutdownLatch.countDown(); - } - } - - public void shutdown() throws InterruptedException { - shutdown.set(true); - shutdownLatch.await(); - } - - public static class ResultDeserializer extends ReferenceDeserializer { - - } - - // use this class to define the data structure of the result record - public static class ResultBean { - private Timestamp ts; - private double current; - private int voltage; - private double phase; - private int groupid; - private String location; - - public Timestamp getTs() { - return ts; - } - - public void setTs(Timestamp ts) { - this.ts = ts; - } - - public double getCurrent() { - return current; - } - - public void setCurrent(double current) { - this.current = current; - } - - public int getVoltage() { - return voltage; - } - - public void setVoltage(int voltage) { - this.voltage = voltage; - } - - public double getPhase() { - return phase; - } - - public void setPhase(double phase) { - this.phase = phase; - } - - public int getGroupid() { - return groupid; - } - - public void setGroupid(int groupid) { - this.groupid = groupid; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - } -} -// ANCHOR_END: consumer_demo diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java new file mode 100644 index 0000000000..4012f2e679 --- /dev/null +++ b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ConsumerLoopFull.java @@ -0,0 +1,357 @@ +package com.taosdata.example; + +import com.alibaba.fastjson.JSON; +import com.taosdata.jdbc.TSDBDriver; +import com.taosdata.jdbc.tmq.*; + +import java.sql.*; +import java.time.Duration; +import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +// ANCHOR: consumer_demo +public class ConsumerLoopFull { + static private Connection connection; + static private Statement statement; + public static TaosConsumer getConsumer() throws SQLException{ +// ANCHOR: create_consumer +Properties config = new Properties(); +config.setProperty("td.connect.type", "jni"); +config.setProperty("bootstrap.servers", "localhost:6030"); +config.setProperty("auto.offset.reset", "latest"); +config.setProperty("msg.with.table.name", "true"); +config.setProperty("enable.auto.commit", "true"); +config.setProperty("auto.commit.interval.ms", "1000"); +config.setProperty("group.id", "group1"); +config.setProperty("client.id", "1"); +config.setProperty("td.connect.user", "root"); +config.setProperty("td.connect.pass", "taosdata"); +config.setProperty("value.deserializer", "com.taosdata.example.ConsumerLoopFull$ResultDeserializer"); +config.setProperty("value.deserializer.encoding", "UTF-8"); + +try { + return new TaosConsumer<>(config); +} catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to create jni consumer, host : " + config.getProperty("bootstrap.servers") + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create consumer", ex); +} catch (Exception e) { + e.printStackTrace(); + throw new SQLException("Failed to create consumer", e); +} +// ANCHOR_END: create_consumer + } + + public static void pollDataExample() throws SQLException { + try (TaosConsumer consumer = getConsumer()){ + // subscribe to the topics + List topics = Collections.singletonList("topic_meters"); + + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + for (int i = 0; i < 50; i++) { + // poll data + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process the data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + } + // unsubscribe the topics + consumer.unsubscribe(); + System.out.println("unsubscribed topics successfully"); + } catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to poll data from topic_meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to poll data from topic_meters", ex); + } + } + + public static void pollExample() throws SQLException { +// ANCHOR: poll_data_code_piece +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + // subscribe to the topics + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + for (int i = 0; i < 50; i++) { + // poll data + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process the data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + } + +} catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to poll data; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to poll data", ex); +} +// ANCHOR_END: poll_data_code_piece +} + + public static void seekExample() throws SQLException { +// ANCHOR: consumer_seek +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + // subscribe to the topics + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + ConsumerRecords records = ConsumerRecords.emptyRecord(); + // make sure we have got some data + while (records.isEmpty()){ + records = consumer.poll(Duration.ofMillis(100)); + } + + for (ConsumerRecord record : records) { + System.out.println("first data polled: " + JSON.toJSONString(record.value())); + Set assignment = consumer.assignment(); + // seek to the beginning of the all partitions + consumer.seekToBeginning(assignment); + System.out.println("assignment seek to beginning successfully"); + break; + } + + // poll data agagin + records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + // process the data here + System.out.println("second data polled: " + JSON.toJSONString(record.value())); + break; + } + + +} catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("seek example failed; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("seek example failed", ex); +} +// ANCHOR_END: consumer_seek + } + + + public static void commitExample() throws SQLException { +// ANCHOR: commit_code_piece +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + consumer.subscribe(topics); + for (int i = 0; i < 50; i++) { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process your data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + if (!records.isEmpty()) { + // after processing the data, commit the offset manually + consumer.commitSync(); + } + } +} catch (SQLException ex){ + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to execute consumer functions. ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to execute consumer functions", ex); +} +// ANCHOR_END: commit_code_piece + } + public static void unsubscribeExample() throws SQLException { + TaosConsumer consumer = getConsumer(); + List topics = Collections.singletonList("topic_meters"); + consumer.subscribe(topics); +// ANCHOR: unsubscribe_data_code_piece + try { + consumer.unsubscribe(); + } catch (SQLException ex){ + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to unsubscribe consumer. ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to unsubscribe consumer", ex); + } finally { + consumer.close(); + } +// ANCHOR_END: unsubscribe_data_code_piece + } + + public static class ResultDeserializer extends ReferenceDeserializer { + + } + // use this class to define the data structure of the result record + public static class ResultBean { + private Timestamp ts; + private double current; + private int voltage; + private double phase; + private int groupid; + private String location; + + public Timestamp getTs() { + return ts; + } + + public void setTs(Timestamp ts) { + this.ts = ts; + } + + public double getCurrent() { + return current; + } + + public void setCurrent(double current) { + this.current = current; + } + + public int getVoltage() { + return voltage; + } + + public void setVoltage(int voltage) { + this.voltage = voltage; + } + + public double getPhase() { + return phase; + } + + public void setPhase(double phase) { + this.phase = phase; + } + + public int getGroupid() { + return groupid; + } + + public void setGroupid(int groupid) { + this.groupid = groupid; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + } + + public static void prepareData() throws SQLException{ + StringBuilder insertQuery = new StringBuilder(); + insertQuery.append("INSERT INTO " + + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + + "VALUES "); + for (int i = 0; i < 10000; i++){ + insertQuery.append("(NOW + ").append(i).append("a, 10.30000, 219, 0.31000) "); + } + try { + int affectedRows = statement.executeUpdate(insertQuery.toString()); + assert affectedRows == 10000; + } catch (SQLException ex) { + System.out.println("Failed to insert data to power.meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to insert data to power.meters", ex); + } + } + public static void prepareMeta() throws SQLException{ + try { + statement.executeUpdate("CREATE DATABASE IF NOT EXISTS power"); + statement.executeUpdate("USE power"); + statement.executeUpdate("CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + statement.executeUpdate("CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM meters"); + } catch (SQLException ex) { + System.out.println("Failed to create db and table, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create db and table", ex); + } + } + + public static void initConnection() throws SQLException { + String url = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + Properties properties = new Properties(); + properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "C"); + properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); + + try { + connection = DriverManager.getConnection(url, properties); + } catch (SQLException ex) { + System.out.println("Failed to create connection, url:" + url + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create connection", ex); + } + try { + statement = connection.createStatement(); + } catch (SQLException ex) { + System.out.println("Failed to create statement, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create statement", ex); + } + System.out.println("Connection created successfully."); + } + public static void closeConnection() throws SQLException { + try { + if (statement != null) { + statement.close(); + } + } catch (SQLException ex) { + System.out.println("Failed to close statement, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to close statement", ex); + } + + try { + if (connection != null) { + connection.close(); + } + } catch (SQLException ex) { + System.out.println("Failed to close connection, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to close connection", ex); + } + System.out.println("Connection closed Successfully."); + } + + + public static void main(String[] args) throws SQLException { + initConnection(); + prepareMeta(); + + // create a single thread executor + ExecutorService executor = Executors.newSingleThreadExecutor(); + + // submit a task + executor.submit(() -> { + try { + // please use one example at a time + pollDataExample(); +// seekExample(); +// pollExample(); +// commitExample(); + unsubscribeExample(); + } catch (SQLException ex) { + System.out.println("Failed to poll data from topic_meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + } + System.out.println("pollDataExample executed successfully"); + }); + + prepareData(); + closeConnection(); + + System.out.println("Data prepared successfully"); + + // 关闭线程池,不再接收新任务 + executor.shutdown(); + + try { + // 等待直到所有任务完成 + boolean result = executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + assert result; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e){ + e.printStackTrace(); + System.out.println("Wait executor termination failed."); + } + + System.out.println("program end."); + } +} +// ANCHOR_END: consumer_demo diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBasicDemo.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBasicDemo.java index 469316efc7..fa2efab2ee 100644 --- a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBasicDemo.java +++ b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBasicDemo.java @@ -2,7 +2,10 @@ package com.taosdata.example; import com.taosdata.jdbc.TSDBPreparedStatement; -import java.sql.*; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; import java.util.ArrayList; import java.util.Random; @@ -24,6 +27,7 @@ public class ParameterBindingBasicDemo { String sql = "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)"; try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) { + for (int i = 1; i <= numOfSubTable; i++) { // set table name pstmt.setTableName("d_bind_" + i); @@ -32,19 +36,35 @@ public class ParameterBindingBasicDemo { pstmt.setTagInt(0, i); pstmt.setTagString(1, "location_" + i); - // set columns + // set column ts + ArrayList tsList = new ArrayList<>(); long current = System.currentTimeMillis(); - for (int j = 0; j < numOfRow; j++) { - pstmt.setTimestamp(1, new Timestamp(current + j)); - pstmt.setFloat(2, random.nextFloat() * 30); - pstmt.setInt(3, random.nextInt(300)); - pstmt.setFloat(4, random.nextFloat()); - pstmt.addBatch(); - } - int [] exeResult = pstmt.executeBatch(); - // you can check exeResult here - System.out.println("insert " + exeResult.length + " rows."); + for (int j = 0; j < numOfRow; j++) + tsList.add(current + j); + pstmt.setTimestamp(0, tsList); + + // set column current + ArrayList currentList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + currentList.add(random.nextFloat() * 30); + pstmt.setFloat(1, currentList); + + // set column voltage + ArrayList voltageList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + voltageList.add(random.nextInt(300)); + pstmt.setInt(2, voltageList); + + // set column phase + ArrayList phaseList = new ArrayList<>(); + for (int j = 0; j < numOfRow; j++) + phaseList.add(random.nextFloat()); + pstmt.setFloat(3, phaseList); + // add column + pstmt.columnDataAddBatch(); } + // execute column + pstmt.columnDataExecuteBatch(); } } catch (SQLException ex) { // handle any errors, please refer to the JDBC specifications for detailed exceptions info diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBatchDemo.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBatchDemo.java deleted file mode 100644 index 60d76eee4f..0000000000 --- a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/ParameterBindingBatchDemo.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.taosdata.example; - -import com.taosdata.jdbc.TSDBPreparedStatement; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Random; - -// ANCHOR: para_bind -public class ParameterBindingBatchDemo { - - // modify host to your own - private static final String host = "127.0.0.1"; - private static final Random random = new Random(System.currentTimeMillis()); - private static final int numOfSubTable = 10, numOfRow = 10; - - public static void main(String[] args) throws SQLException { - - String jdbcUrl = "jdbc:TAOS://" + host + ":6030/"; - try (Connection conn = DriverManager.getConnection(jdbcUrl, "root", "taosdata")) { - - init(conn); - - String sql = "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)"; - - try (TSDBPreparedStatement pstmt = conn.prepareStatement(sql).unwrap(TSDBPreparedStatement.class)) { - - for (int i = 1; i <= numOfSubTable; i++) { - // set table name - pstmt.setTableName("d_bind_" + i); - - // set tags - pstmt.setTagInt(0, i); - pstmt.setTagString(1, "location_" + i); - - // set column ts - ArrayList tsList = new ArrayList<>(); - long current = System.currentTimeMillis(); - for (int j = 0; j < numOfRow; j++) - tsList.add(current + j); - pstmt.setTimestamp(0, tsList); - - // set column current - ArrayList f1List = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - f1List.add(random.nextFloat() * 30); - pstmt.setFloat(1, f1List); - - // set column voltage - ArrayList f2List = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - f2List.add(random.nextInt(300)); - pstmt.setInt(2, f2List); - - // set column phase - ArrayList f3List = new ArrayList<>(); - for (int j = 0; j < numOfRow; j++) - f3List.add(random.nextFloat()); - pstmt.setFloat(3, f3List); - // add column - pstmt.columnDataAddBatch(); - } - // execute column - pstmt.columnDataExecuteBatch(); - } - } catch (SQLException ex) { - // handle any errors, please refer to the JDBC specifications for detailed exceptions info - System.out.println("Failed to insert to table meters using stmt, url: " + jdbcUrl + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); - } - } - - private static void init(Connection conn) throws SQLException { - try (Statement stmt = conn.createStatement()) { - stmt.execute("CREATE DATABASE IF NOT EXISTS power"); - stmt.execute("USE power"); - stmt.execute("CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - } -} -// ANCHOR_END: para_bind diff --git a/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java new file mode 100644 index 0000000000..d8084eb9f6 --- /dev/null +++ b/examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/WsConsumerLoopFull.java @@ -0,0 +1,358 @@ +package com.taosdata.example; + +import com.alibaba.fastjson.JSON; +import com.taosdata.jdbc.TSDBDriver; +import com.taosdata.jdbc.tmq.*; + +import java.sql.*; +import java.time.Duration; +import java.util.Collections; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +// ANCHOR: consumer_demo +public class WsConsumerLoopFull { + static private Connection connection; + static private Statement statement; + public static TaosConsumer getConsumer() throws SQLException{ +// ANCHOR: create_consumer +Properties config = new Properties(); +config.setProperty("td.connect.type", "ws"); +config.setProperty("bootstrap.servers", "localhost:6041"); +config.setProperty("auto.offset.reset", "latest"); +config.setProperty("msg.with.table.name", "true"); +config.setProperty("enable.auto.commit", "true"); +config.setProperty("auto.commit.interval.ms", "1000"); +config.setProperty("group.id", "group1"); +config.setProperty("client.id", "client1"); +config.setProperty("td.connect.user", "root"); +config.setProperty("td.connect.pass", "taosdata"); +config.setProperty("value.deserializer", "com.taosdata.example.WsConsumerLoopFull$ResultDeserializer"); +config.setProperty("value.deserializer.encoding", "UTF-8"); + +try { + return new TaosConsumer<>(config); + } catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to create websocket consumer, host : " + config.getProperty("bootstrap.servers") + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create consumer", ex); + } catch (Exception e) { + e.printStackTrace(); + throw new SQLException("Failed to create consumer", e); + } +// ANCHOR_END: create_consumer +} + + public static void pollDataExample() throws SQLException { + try (TaosConsumer consumer = getConsumer()){ + // subscribe to the topics + List topics = Collections.singletonList("topic_meters"); + + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + for (int i = 0; i < 50; i++) { + // poll data + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process the data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + } + // unsubscribe the topics + consumer.unsubscribe(); + System.out.println("unsubscribed topics successfully"); + } catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to poll data from topic_meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to poll data from topic_meters", ex); + } + } + + public static void pollExample() throws SQLException { +// ANCHOR: poll_data_code_piece +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + // subscribe to the topics + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + for (int i = 0; i < 50; i++) { + // poll data + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process the data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + } + +} catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to poll data; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to poll data", ex); +} +// ANCHOR_END: poll_data_code_piece + } + + public static void seekExample() throws SQLException { +// ANCHOR: consumer_seek +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + // subscribe to the topics + consumer.subscribe(topics); + System.out.println("subscribe topics successfully"); + ConsumerRecords records = ConsumerRecords.emptyRecord(); + // make sure we have got some data + while (records.isEmpty()){ + records = consumer.poll(Duration.ofMillis(100)); + } + + for (ConsumerRecord record : records) { + System.out.println("first data polled: " + JSON.toJSONString(record.value())); + Set assignment = consumer.assignment(); + // seek to the beginning of the all partitions + consumer.seekToBeginning(assignment); + System.out.println("assignment seek to beginning successfully"); + break; + } + + // poll data agagin + records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + // process the data here + System.out.println("second data polled: " + JSON.toJSONString(record.value())); + break; + } +} catch (SQLException ex) { + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("seek example failed; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("seek example failed", ex); +} +// ANCHOR_END: consumer_seek + } + + + public static void commitExample() throws SQLException { +// ANCHOR: commit_code_piece +try (TaosConsumer consumer = getConsumer()){ + List topics = Collections.singletonList("topic_meters"); + + consumer.subscribe(topics); + for (int i = 0; i < 50; i++) { + ConsumerRecords records = consumer.poll(Duration.ofMillis(100)); + for (ConsumerRecord record : records) { + ResultBean bean = record.value(); + // process your data here + System.out.println("data: " + JSON.toJSONString(bean)); + } + if (!records.isEmpty()) { + // after processing the data, commit the offset manually + consumer.commitSync(); + } + } +} catch (SQLException ex){ + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to execute consumer functions. ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to execute consumer functions", ex); +} +// ANCHOR_END: commit_code_piece + } + public static void unsubscribeExample() throws SQLException { + TaosConsumer consumer = getConsumer(); + List topics = Collections.singletonList("topic_meters"); + consumer.subscribe(topics); +// ANCHOR: unsubscribe_data_code_piece +try { + consumer.unsubscribe(); +} catch (SQLException ex){ + // handle any errors, please refer to the JDBC specifications for detailed exceptions info + System.out.println("Failed to unsubscribe consumer. ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to unsubscribe consumer", ex); +} finally { + consumer.close(); +} +// ANCHOR_END: unsubscribe_data_code_piece + } + +public static class ResultDeserializer extends ReferenceDeserializer { + +} +// use this class to define the data structure of the result record +public static class ResultBean { + private Timestamp ts; + private double current; + private int voltage; + private double phase; + private int groupid; + private String location; + + public Timestamp getTs() { + return ts; + } + + public void setTs(Timestamp ts) { + this.ts = ts; + } + + public double getCurrent() { + return current; + } + + public void setCurrent(double current) { + this.current = current; + } + + public int getVoltage() { + return voltage; + } + + public void setVoltage(int voltage) { + this.voltage = voltage; + } + + public double getPhase() { + return phase; + } + + public void setPhase(double phase) { + this.phase = phase; + } + + public int getGroupid() { + return groupid; + } + + public void setGroupid(int groupid) { + this.groupid = groupid; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } +} + + public static void prepareData() throws SQLException{ + StringBuilder insertQuery = new StringBuilder(); + insertQuery.append("INSERT INTO " + + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + + "VALUES "); + for (int i = 0; i < 10000; i++){ + insertQuery.append("(NOW + ").append(i).append("a, 10.30000, 219, 0.31000) "); + } + try { + int affectedRows = statement.executeUpdate(insertQuery.toString()); + assert affectedRows == 10000; + } catch (SQLException ex) { + System.out.println("Failed to insert data to power.meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to insert data to power.meters", ex); + } + } + public static void prepareMeta() throws SQLException{ + try { + statement.executeUpdate("CREATE DATABASE IF NOT EXISTS power"); + statement.executeUpdate("USE power"); + statement.executeUpdate("CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + statement.executeUpdate("CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM meters"); + } catch (SQLException ex) { + System.out.println("Failed to create db and table, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create db and table", ex); + } + } + + public static void initConnection() throws SQLException { + String url = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + Properties properties = new Properties(); + properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "C"); + properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); + + try { + connection = DriverManager.getConnection(url, properties); + } catch (SQLException ex) { + System.out.println("Failed to create connection, url:" + url + "; ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create connection", ex); + } + try { + statement = connection.createStatement(); + } catch (SQLException ex) { + System.out.println("Failed to create statement, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to create statement", ex); + } + System.out.println("Connection created successfully."); + } + public static void closeConnection() throws SQLException { + try { + if (statement != null) { + statement.close(); + } + } catch (SQLException ex) { + System.out.println("Failed to close statement, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to close statement", ex); + } + + try { + if (connection != null) { + connection.close(); + } + } catch (SQLException ex) { + System.out.println("Failed to close connection, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + throw new SQLException("Failed to close connection", ex); + } + System.out.println("Connection closed Successfully."); + } + + + public static void main(String[] args) throws SQLException { + initConnection(); + prepareMeta(); + + // create a single thread executor + ExecutorService executor = Executors.newSingleThreadExecutor(); + + // submit a task + executor.submit(() -> { + try { + // please use one example at a time + pollDataExample(); +// seekExample(); +// pollExample(); +// commitExample(); + unsubscribeExample(); + } catch (SQLException ex) { + System.out.println("Failed to poll data from topic_meters, ErrCode:" + ex.getErrorCode() + "; ErrMessage: " + ex.getMessage()); + } + System.out.println("pollDataExample executed successfully"); + }); + + prepareData(); + closeConnection(); + + System.out.println("Data prepared successfully"); + + // 关闭线程池,不再接收新任务 + executor.shutdown(); + + try { + // 等待直到所有任务完成 + boolean result = executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + assert result; + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } catch (Exception e){ + e.printStackTrace(); + System.out.println("Wait executor termination failed."); + } + + System.out.println("program end."); + } +} +// ANCHOR_END: consumer_demo From 779c46b85f75f5c06d899595afcb351557609cd3 Mon Sep 17 00:00:00 2001 From: Yaming Pei Date: Thu, 1 Aug 2024 21:40:59 +0800 Subject: [PATCH 2/7] The Connector section of the official website reconstructs the C language interface description --- docs/zh/14-reference/05-connector/10-cpp.mdx | 202 +++++++++++-------- 1 file changed, 115 insertions(+), 87 deletions(-) diff --git a/docs/zh/14-reference/05-connector/10-cpp.mdx b/docs/zh/14-reference/05-connector/10-cpp.mdx index d4761ee5c4..2e7a53a464 100644 --- a/docs/zh/14-reference/05-connector/10-cpp.mdx +++ b/docs/zh/14-reference/05-connector/10-cpp.mdx @@ -224,131 +224,161 @@ int taos_print_row(char *str, TAOS_ROW row, TAOS_FIELD *fields, int num_fields) 基础 API 用于完成创建数据库连接等工作,为其它 API 的执行提供运行时环境。 - `int taos_init()` - - 初始化运行环境。如果没有主动调用该 API,那么调用 `taos_connect()` 时驱动将自动调用该 API,故程序一般无需手动调用。 + - **接口说明**:初始化运行环境。如果没有主动调用该 API,那么调用 `taos_connect()` 时驱动将自动调用该 API,故程序一般无需手动调用。 + - **返回值**:待补充,未找到相关资料。 - `void taos_cleanup()` - - 清理运行环境,应用退出前应调用。 + - **接口说明**:清理运行环境,应用退出前应调用。 - `int taos_options(TSDB_OPTION option, const void * arg, ...)` - - 设置客户端选项,目前支持区域设置(`TSDB_OPTION_LOCALE`)、字符集设置(`TSDB_OPTION_CHARSET`)、时区设置(`TSDB_OPTION_TIMEZONE`)、配置文件路径设置(`TSDB_OPTION_CONFIGDIR`)。区域设置、字符集、时区默认为操作系统当前设置。 + - **接口说明**:设置客户端选项,目前支持区域设置(`TSDB_OPTION_LOCALE`)、字符集设置(`TSDB_OPTION_CHARSET`)、时区设置(`TSDB_OPTION_TIMEZONE`)、配置文件路径设置(`TSDB_OPTION_CONFIGDIR`)。区域设置、字符集、时区默认为操作系统当前设置。 + - **参数说明**: + - `option`:[入参] 设置项类型。 + - `arg`:[入参] 设置项值。 + - **返回值**:`0`:成功,`-1`:失败。 - `char *taos_get_client_info()` + - **接口说明**:获取客户端版本信息。 + - **返回值**:返回客户端版本信息。 - 获取客户端版本信息。 - -- `TAOS *taos_connect(const char *host, const char *user, const char *pass, const char *db, int port)` - - 创建数据库连接,初始化连接上下文。其中需要用户提供的参数包含: - - - host:TDengine 集群中任一节点的 FQDN - - user:用户名 - - pass:密码 - - db: 数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库 - - port:taosd 程序监听的端口 - - 返回值为空表示失败。应用程序需要保存返回的参数,以便后续使用。 - +- `TAOS *taos_connect(const char *ip, const char *user, const char *pass, const char *db, uint16_t port);` + - **接口说明**:创建数据库连接,初始化连接上下文。 + - **参数说明**: + - ip:[入参] TDengine 集群中任一节点的 FQDN。 + - user:[入参] 用户名。 + - pass:[入参] 密码。 + - db:[入参] 数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库。 + - port:[入参] taosd 程序监听的端口。 + - **返回值**:返回数据库连接,返回值为空表示失败。应用程序需要保存返回的参数,以便后续使用。 :::info 同一进程可以根据不同的 host/port 连接多个 TDengine 集群 - ::: - `TAOS *taos_connect_auth(const char *host, const char *user, const char *auth, const char *db, uint16_t port)` - - 功能同 taos_connect。除 pass 参数替换为 auth 外,其他参数同 taos_connect。 - - - auth: 原始密码取 32 位小写 md5 + - **接口说明**:功能同 taos_connect。除 pass 参数替换为 auth 外,其他参数同 taos_connect。 + - **参数说明**: + - ip:[入参] TDengine 集群中任一节点的 FQDN。 + - user:[入参] 用户名。 + - auth: [入参] 原始密码取 32 位小写 md5。 + - db:[入参] 数据库名称,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库。 + - port:[入参] taosd 程序监听的端口。 + - **返回值**:返回数据库连接,返回值为空表示失败。应用程序需要保存返回的参数,以便后续使用。 - `char *taos_get_server_info(TAOS *taos)` - - 获取服务端版本信息。 + - **接口说明**:获取服务端版本信息。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - **返回值**:返回获取服务端版本信息。 - `int taos_select_db(TAOS *taos, const char *db)` + - **接口说明**:将当前的缺省数据库设置为 `db`。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - db:[入参] 数据库名称。 + - **返回值**:`0`:成功,`非0`:失败,详情请参考错误码。待补充。 - 将当前的缺省数据库设置为 `db`。 - - `int taos_get_current_db(TAOS *taos, char *database, int len, int *required)` - - - database,len为用户在外面申请的空间,内部会把当前db赋值到database里。 - - 只要是没有正常把db名赋值到database中(包括截断),返回错误,返回值为-1,然后用户可以通过 taos_errstr(NULL) 来获取错误提示。 - - 如果,database == NULL 或者 len\<=0 返回错误,required里保存存储db需要的空间(包含最后的'\0') - - 如果,len 小于 存储db需要的空间(包含最后的'\0'),返回错误,database里赋值截断的数据,以'\0'结尾。 - - 如果,len 大于等于 存储db需要的空间(包含最后的'\0'),返回正常0,database里赋值以'\0‘结尾的db名。 + - **接口说明**:获取当前数据库名称。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - database:[出参] 存储当前数据库名称。 + - len:[入参] database 的空间大小。 + - required:[出参] 存储当前数据库名称所需的空间(包含最后的'\0')。 + - **返回值**:`0`:成功,`-1`:失败,详情请调用 taos_errstr(NULL) 函数来获取错误提示。 + - 如果,database == NULL 或者 len\<=0 返回失败。 + - 如果,len 小于 存储数据库名称所需的空间(包含最后的'\0'),返回失败,database 里赋值截断的数据,以'\0'结尾。 + - 如果,len 大于等于 存储数据库名称所需的空间(包含最后的'\0'),返回成功,database 里赋值以'\0‘结尾数据库名称。 - `int taos_set_notify_cb(TAOS *taos, __taos_notify_fn_t fp, void *param, int type)` - - 设置事件回调函数。 - - - fp 事件回调函数指针。函数声明:typedef void (*__taos_notify_fn_t)(void *param, void *ext, int type);其中, param 为用户自定义参数,ext 为扩展参数(依赖事件类型,针对 TAOS_NOTIFY_PASSVER 返回用户密码版本),type 为事件类型 - - param 用户自定义参数 - - type 事件类型。取值范围:1)TAOS_NOTIFY_PASSVER: 用户密码改变 + - **接口说明**:设置事件回调函数。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - fp:[入参] 事件回调函数指针。函数声明:typedef void (*__taos_notify_fn_t)(void *param, void *ext, int type);其中, param 为用户自定义参数,ext 为扩展参数(依赖事件类型,针对 TAOS_NOTIFY_PASSVER 返回用户密码版本),type 为事件类型。 + - param:[入参] 用户自定义参数。 + - type:[入参] 事件类型。取值范围:1)TAOS_NOTIFY_PASSVER: 用户密码改变。 + - **返回值**:`0`:成功,`-1`:失败,详情请调用 taos_errstr(NULL) 函数来获取错误提示。 - `void taos_close(TAOS *taos)` - - 关闭连接,其中`taos`是 `taos_connect()` 返回的句柄。 + - **接口说明**:关闭连接。 + - **参数说明**: + - taos:[入参] 数据库连接。 ### 同步查询 API 本小节介绍 API 均属于同步接口。应用调用后,会阻塞等待响应,直到获得返回结果或错误信息。 - `TAOS_RES* taos_query(TAOS *taos, const char *sql)` - - 执行 SQL 语句,可以是 DQL、DML 或 DDL 语句。 其中的 `taos` 参数是通过 `taos_connect()` 获得的句柄。不能通过返回值是否是 `NULL` 来判断执行结果是否失败,而是需要用 `taos_errno()` 函数解析结果集中的错误代码来进行判断。 + - **接口说明**:执行 SQL 语句,可以是 DQL、DML 或 DDL 语句。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - sql:[入参] 需要执行 SQL 语句。 + - **返回值**:不能通过返回值是否是 `NULL` 来判断执行结果是否失败,而是需要调用 `taos_errno()` 函数解析结果集中的错误代码来进行判断。 + - taos_errno 返回值:`0`:成功,`-1`:失败,详情请调用 taos_errstr 函数来获取错误提示。 - `int taos_result_precision(TAOS_RES *res)` - - 返回结果集时间戳字段的精度,`0` 代表毫秒,`1` 代表微秒,`2` 代表纳秒。 + - **接口说明**:返回结果集时间戳字段的精度类别。 + - **参数说明**: + - res:[入参] 结果集。 + - **返回值**:`0`:毫秒,`1`:微秒,`2`:纳秒。 - `TAOS_ROW taos_fetch_row(TAOS_RES *res)` - - 按行获取查询结果集中的数据。 + - **接口说明**:按行获取查询结果集中的数据。 + - **参数说明**: + - res:[入参] 查询结果集。 + - **返回值**:`非NULL`:成功,`NULL`:失败,详情请调用 taos_errstr(NULL) 函数来获取错误提示。 - `int taos_fetch_block(TAOS_RES *res, TAOS_ROW *rows)` - - 批量获取查询结果集中的数据,返回值为获取到的数据的行数。 + - **接口说明**:批量获取查询结果集中的数据。 + - **参数说明**: + - res:[入参] 查询结果集。 + - rows:[出参] 用于存储从结果集中获取的行。 + - **返回值**:返回值为获取到的数据的行数,如果没有更多的行则返回 0。 - `int taos_num_fields(TAOS_RES *res)` 和 `int taos_field_count(TAOS_RES *res)` - - 这两个 API 等价,用于获取查询结果集中的列数。 + - **接口说明**:这两个 API 等价,用于获取查询结果集中的列数。 + - **参数说明**: + - res:[入参] 查询结果集。 + - **返回值**:返回值为结果集中列的数量。 - `int* taos_fetch_lengths(TAOS_RES *res)` - - 获取结果集中每个字段的长度。返回值是一个数组,其长度为结果集的列数。 + - **接口说明**:获取结果集中每个字段的长度。 + - **参数说明**: + - res:[入参] 结果集。 + - **返回值**:返回值是一个数组,其长度为结果集的列数。 - `int taos_affected_rows(TAOS_RES *res)` - - 获取被所执行的 SQL 语句影响的行数。 + - **接口说明**:获取被所执行的 SQL 语句影响的行数。 + - **参数说明**: + - res:[入参] 结果集。 + - **返回值**:返回值表示受影响的行数。 - `TAOS_FIELD *taos_fetch_fields(TAOS_RES *res)` - - 获取查询结果集每列数据的属性(列的名称、列的数据类型、列的长度),与 `taos_num_fields()` 配合使用,可用来解析 `taos_fetch_row()` 返回的一个元组(一行)的数据。 `TAOS_FIELD` 的结构如下: - -```c -typedef struct taosField { - char name[65]; // column name - uint8_t type; // data type - int16_t bytes; // length, in bytes -} TAOS_FIELD; -``` + - **接口说明**:获取查询结果集每列数据的属性(列的名称、列的数据类型、列的长度),与 `taos_num_fields()` 配合使用,可用来解析 `taos_fetch_row()` 返回的一个元组(一行)的数据。 + - **参数说明**: + - res:[入参] 查询结果集。 + - **返回值**:`非NULL`:成功,返回一个指向 TAOS_FIELD 结构体的指针,每个元素代表一列的元数据。`NULL`:失败。 - `void taos_stop_query(TAOS_RES *res)` - - 停止当前查询的执行。 + - **接口说明**:停止当前查询的执行。 + - **参数说明**: + - res:[入参] 查询结果集。 - `void taos_free_result(TAOS_RES *res)` - - 释放查询结果集以及相关的资源。查询完成后,务必调用该 API 释放资源,否则可能导致应用内存泄露。但也需注意,释放资源后,如果再调用 `taos_consume()` 等获取查询结果的函数,将导致应用崩溃。 + - **接口说明**:释放查询结果集以及相关的资源。查询完成后,务必调用该 API 释放资源,否则可能导致应用内存泄露。但也需注意,释放资源后,如果再调用 `taos_consume()` 等获取查询结果的函数,将导致应用崩溃。 + - **参数说明**: + - res:[入参] 查询结果集。 - `char *taos_errstr(TAOS_RES *res)` - - 获取最近一次 API 调用失败的原因,返回值为字符串标识的错误提示信息。 + - **接口说明**:获取最近一次 API 调用失败的原因,返回值为字符串标识的错误提示信息。 + - **参数说明**: + - res:[入参] 结果集。 + - **返回值**:字符串标识的错误提示信息。 - `int taos_errno(TAOS_RES *res)` - - 获取最近一次 API 调用失败的原因,返回值为错误代码。 + - **接口说明**:获取最近一次 API 调用失败的原因,返回值为错误代码。 + - **参数说明**: + - res:[入参] 结果集。 + - **返回值**:字符串标识的错误提示信息。 :::note 2.0 及以上版本 TDengine 推荐数据库应用的每个线程都建立一个独立的连接,或基于线程建立连接池。而不推荐在应用中将该连接 (TAOS\*) 结构体传递到不同的线程共享使用。基于 TAOS 结构体发出的查询、写入等操作具有多线程安全性,但 “USE statement” 等状态量有可能在线程之间相互干扰。此外,C 语言的连接器可以按照需求动态建立面向数据库的新连接(该过程对用户不可见),同时建议只有在程序最后退出的时候才调用 `taos_close()` 关闭连接。 @@ -365,20 +395,18 @@ TDengine 还提供性能更高的异步 API 处理数据插入、查询操作。 异步 API 对于使用者的要求相对较高,用户可根据具体应用场景选择性使用。下面是两个重要的异步 API: - `void taos_query_a(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, int code), void *param);` - - 异步执行 SQL 语句。 - - - taos:调用 `taos_connect()` 返回的数据库连接 - - sql:需要执行的 SQL 语句 - - fp:用户定义的回调函数,其第三个参数 `code` 用于指示操作是否成功,`0` 表示成功,负数表示失败(调用 `taos_errstr()` 可获取失败原因)。应用在定义回调函数的时候,主要处理第二个参数 `TAOS_RES *`,该参数是查询返回的结果集 - - param:应用提供一个用于回调的参数 + - **接口说明**:异步执行 SQL 语句。 + - **参数说明**: + - taos:[入参] 数据库连接。 + - sql: [入参] 需要执行的 SQL 语句。 + - fp:用户定义的回调函数,其第三个参数 `code` 用于指示操作是否成功,`0` 表示成功,负数表示失败(调用 `taos_errstr()` 可获取失败原因)。应用在定义回调函数的时候,主要处理第二个参数 `TAOS_RES *`,该参数是查询返回的结果集。 + - param:应用提供的用于回调的参数。 - `void taos_fetch_rows_a(TAOS_RES *res, void (*fp)(void *param, TAOS_RES *, int numOfRows), void *param);` - - 批量获取异步查询的结果集,只能与 `taos_query_a()` 配合使用。其中: - - - res:`taos_query_a()` 回调时返回的结果集 - - fp:回调函数。其参数 `param` 是用户可定义的传递给回调函数的参数结构体;`numOfRows` 是获取到的数据的行数(不是整个查询结果集的函数)。 在回调函数中,应用可以通过调用 `taos_fetch_row()` 前向迭代获取批量记录中每一行记录。读完一块内的所有记录后,应用需要在回调函数中继续调用 `taos_fetch_rows_a()` 获取下一批记录进行处理,直到返回的记录数 `numOfRows` 为零(结果返回完成)或记录数为负值(查询出错)。 + - **接口说明**: 批量获取异步查询的结果集,只能与 `taos_query_a()` 配合使用。 + - **参数说明**: + - res:`taos_query_a()` 回调时返回的结果集。 + - fp:回调函数。其参数 `param` 是用户可定义的传递给回调函数的参数结构体;`numOfRows` 是获取到的数据的行数(不是整个查询结果集的函数)。 在回调函数中,应用可以通过调用 `taos_fetch_row()` 前向迭代获取批量记录中每一行记录。读完一块内的所有记录后,应用需要在回调函数中继续调用 `taos_fetch_rows_a()` 获取下一批记录进行处理,直到返回的记录数 `numOfRows` 为零(结果返回完成)或记录数为负值(查询出错)。 TDengine 的异步 API 均采用非阻塞调用模式。应用程序可以用多线程同时打开多张表,并可以同时对每张打开的表进行查询或者插入操作。需要指出的是,**客户端应用必须确保对同一张表的操作完全串行化**,即对同一个表的插入或查询操作未完成时(未返回时),不能够执行第二个插入或查询操作。 From ef1884d675a2a227a9080380ebad3e7f0ab04cbf Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Fri, 2 Aug 2024 08:49:41 +0800 Subject: [PATCH 3/7] add rust api --- docs/zh/14-reference/05-connector/26-rust.mdx | 397 +++++++++++++++++- 1 file changed, 396 insertions(+), 1 deletion(-) diff --git a/docs/zh/14-reference/05-connector/26-rust.mdx b/docs/zh/14-reference/05-connector/26-rust.mdx index 2cdfdc9e41..f6c9e5d688 100644 --- a/docs/zh/14-reference/05-connector/26-rust.mdx +++ b/docs/zh/14-reference/05-connector/26-rust.mdx @@ -607,7 +607,402 @@ stmt.execute()?; 一个可运行的示例请见 [GitHub 上的示例](https://github.com/taosdata/taos-connector-rust/blob/main/examples/bind.rs)。 -其他相关结构体 API 使用说明请移步 Rust 文档托管网页:\。 +## API 参考 + +Rust 连接器的接口分为同步接口和异步接口,一般同步接口是由异步接口实现,方法签名除 async 关键字外基本相同。对于同步接口和异步接口功能一样的接口,本文档只提供同步接口的说明。 +对于 WebSocket 连接和原生连接两种方式,除了建立连接的 DSN 不同,其余接口调用没有区别。 + +### 连接功能 +#### DSN + +TaosBuilder 通过 DSN 连接描述字符串创建一个连接构造器。 +DSN 描述字符串基本结构如下: + +```text +[+]://[[:@]:][/][?=[&=]] +|------|------------|---|-----------|-----------|------|------|------------|-----------------------| +|driver| protocol | | username | password | host | port | database | params | +``` + +各部分意义见下表: + +- **driver**: 必须指定驱动名以便连接器选择何种方式创建连接,支持如下驱动名: + - **taos**: 表名使用 TDengine 连接器驱动。 + - **tmq**: 使用 TMQ 订阅数据。 + - **http/ws**: 使用 Websocket 创建连接。 + - **https/wss**: 在 Websocket 连接方式下显示启用 SSL/TLS 连接。 +- **protocol**: 显示指定以何种方式建立连接,例如:`taos+ws://localhost:6041` 指定以 Websocket 方式建立连接。 +- **username/password**: 用于创建连接的用户名及密码。 +- **host/port**: 指定创建连接的服务器及端口,当不指定服务器地址及端口时(`taos://`),原生连接默认为 `localhost:6030`,Websocket 连接默认为 `localhost:6041` 。 +- **database**: 指定默认连接的数据库名,可选参数。 +- **params**:其他可选参数。 + +一个完整的 DSN 描述字符串示例如下:`taos+ws://localhost:6041/test`, 表示使用 Websocket(`ws`)方式通过 `6041` 端口连接服务器 `localhost`,并指定默认数据库为 `test`。 + +#### TaosBuilder +TaosBuilder 结构体提供了建立连接,检查连接,以及获取服务端版本号等功能。 + +- `fn available_params() -> &'static [&'static str]` + - **接口说明**:获取DSN中可用的参数列表。 + - **返回值**:返回静态字符串切片的引用,包含可用的参数名称。 + +- `fn from_dsn(dsn: D) -> RawResult` + - **接口说明**:使用DSN字符串创建连接,不检查连接。 + - **参数说明**: + - `dsn`:DSN字符串或可转换为DSN的类型。 + - **返回值**:成功时返回自身类型的 `RawResult`,失败时返回错误。 + +- `fn client_version() -> &'static str` + - **接口说明**:获取客户端版本。 + - **返回值**:返回客户端版本的静态字符串。 + +- `fn ping(&self, _: &mut Self::Target) -> RawResult<()>` + - **接口说明**:检查连接是否仍然存活。 + - **参数说明**: + - `_`:目标连接的可变引用。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn ready(&self) -> bool` + - **接口说明**:检查是否准备好连接。 + - **返回值**:大多数情况下返回true,表示地址准备好连接。 + +- `fn build(&self) -> RawResult` + - **接口说明**:从此结构创建新的连接。 + - **返回值**:成功时返回目标连接类型的 `RawResult`,失败时返回错误。 + +### 执行 SQL +执行 SQL 主要涉及到 Taos 结构体,以及结果集 ResultSet 结构体,还有列信息 Field。 +#### Taos +Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无模式写入,以及一些常用数据库查询的封装(如创建数据库,获取) + +- `pub fn is_native(&self) -> bool` + - **接口说明**:判断连接是否使用本地协议。 + - **返回值**:如果使用本地协议,则返回 `true`,否则返回 `false`。 + +- `pub fn is_ws(&self) -> bool` + - **接口说明**:判断连接是否使用websocket协议。 + - **返回值**:如果使用websocket协议,则返回 `true`,否则返回 `false`。 + +- `fn query>(&self, sql: T) -> RawResult` + - **接口说明**:执行SQL查询。 + - **参数说明**: + - `sql`:要执行的SQL语句。 + - **返回值**:成功时返回结果集 `ResultSet` 的 `RawResult`,失败时返回错误。 + +- `fn query_with_req_id>(&self, sql: T, req_id: u64) -> RawResult` + - **接口说明**:带请求ID执行SQL查询。 + - **参数说明**: + - `sql`:要执行的SQL语句。 + - `req_id`:请求ID。 + - **返回值**:成功时返回结果集 `ResultSet` 的 `RawResult`,失败时返回错误。 + +- `fn exec>(&self, sql: T) -> RawResult` + - **接口说明**:执行SQL语句。 + - **参数说明**: + - `sql`:要执行的SQL语句。 + - **返回值**:成功时返回受影响的行数,失败时返回错误。 + +- `fn exec_many, I: IntoIterator>(&self, input: I) -> RawResult` + - **接口说明**:批量执行SQL语句。 + - **参数说明**: + - `input`:要执行的SQL语句集合。 + - **返回值**:成功时返回总共受影响的行数,失败时返回错误。 + +- `fn query_one, O: DeserializeOwned>(&self, sql: T) -> RawResult>` + - **接口说明**:执行SQL查询并返回单个结果。 + - **参数说明**: + - `sql`:要执行的SQL语句。 + - **返回值**:成功时返回可选的结果对象,失败时返回错误。 + +- `fn server_version(&self) -> RawResult>` + - **接口说明**:获取服务器版本。 + - **返回值**:成功时返回服务器版本字符串的 `RawResult`,失败时返回错误。 + +- `fn create_topic(&self, name: impl AsRef, sql: impl AsRef) -> RawResult<()>` + - **接口说明**:创建主题。 + - **参数说明**: + - `name`:主题名称。 + - `sql`:关联的SQL语句。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn databases(&self) -> RawResult>` + - **接口说明**:获取数据库列表。 + - **返回值**:成功时返回数据库列表的 `RawResult`,失败时返回错误。 + +- `fn topics(&self) -> RawResult>` + - **接口说明**:获取主题信息。 + - **返回值**:成功时返回主题列表的 `RawResult`,失败时返回错误。 + +- `fn describe(&self, table: &str) -> RawResult` + - **接口说明**:描述表结构。 + - **参数说明**: + - `table`:表名称。 + - **返回值**:成功时返回表描述的 `RawResult`,失败时返回错误。 + +- `fn database_exists(&self, name: &str) -> RawResult` + - **接口说明**:检查数据库是否存在。 + - **参数说明**: + - `name`:数据库名称。 + - **返回值**:成功时返回布尔值的 `RawResult`,指示数据库是否存在,失败时返回错误。 + +- `fn put(&self, data: &SmlData) -> RawResult<()>` + - **接口说明**:写入无模式数据。 + - **参数说明**: + - `data`:无模式数据。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + + +#### ResultSet +ResultSet 结构体提供了结果集的一些方法,可以用来获取结果集的数据和元数据。 + +- `fn affected_rows(&self) -> i32` + - **接口说明**:获取受影响的行数。 + - **返回值**:受影响的行数,类型为 `i32`。 + +- `fn precision(&self) -> Precision` + - **接口说明**:获取精度信息。 + - **返回值**:精度信息,类型为 `Precision`。 + +- `fn fields(&self) -> &[Field]` + - **接口说明**:获取字段信息。见下文 Feild 结构体描述。 + - **返回值**:字段信息数组的引用。 + +- `fn summary(&self) -> (usize, usize)` + - **接口说明**:获取摘要信息。 + - **返回值**:包含两个 `usize` 类型的元组,分别表示某些统计信息。 + +- `fn num_of_fields(&self) -> usize` + - **接口说明**:获取字段数量。 + - **返回值**:字段数量,类型为 `usize`。 + +- `fn blocks(&mut self) -> IBlockIter<'_, Self>` + - **接口说明**:获取原始数据块的迭代器。 + - **返回值**:原始数据块的迭代器,类型为 `IBlockIter<'_, Self>`。 + +- `fn rows(&mut self) -> IRowsIter<'_, Self>` + - **接口说明**:获取按行查询的迭代器。 + - **返回值**:按行查询的迭代器,类型为 `IRowsIter<'_, Self>`。 + +- `fn deserialize(&mut self) -> Map, fn(_: Result, Error>) -> Result>` + - **接口说明**:反序列化行数据。 + - **泛型参数**: + - `T`:目标类型,需实现 `DeserializeOwned`。 + - **返回值**:反序列化结果的映射,类型为 `Map, fn(_: Result, Error>) -> Result>`。 + +- `fn to_rows_vec(&mut self) -> Result>, Error>` + - **接口说明**:将结果集转换为值的二维向量。 + - **返回值**:成功时返回值的二维向量,失败时返回错误,类型为 `Result>, Error>`。 + +#### Feild +Feild 结构体提供了字段信息的一些方法。 + +- `pub const fn empty() -> Field` + - **接口说明**:创建一个空的 `Field` 实例。 + - **返回值**:返回一个空的 `Field` 实例。 + +- `pub fn new(name: impl Into, ty: Ty, bytes: u32) -> Field` + - **接口说明**:创建一个新的 `Field` 实例。 + - **参数说明**: + - `name`:字段名称。 + - `ty`:字段类型。 + - `bytes`:字段数据长度。 + - **返回值**:返回一个新的 `Field` 实例。 + +- `pub fn name(&self) -> &str` + - **接口说明**:获取字段名称。 + - **返回值**:返回字段的名称。 + +- `pub fn escaped_name(&self) -> String` + - **接口说明**:获取转义后的字段名称。 + - **返回值**:返回转义后的字段名称。 + +- `pub const fn ty(&self) -> Ty` + - **接口说明**:获取字段类型。 + - **返回值**:返回字段的类型。 + +- `pub const fn bytes(&self) -> u32` + - **接口说明**:获取字段的预设长度。 + - **返回值**:对于变长数据类型,返回其预设长度;对于其他类型,返回其字节宽度。 + +- `pub fn to_c_field(&self) -> c_field_t` + - **接口说明**:将 `Field` 实例转换为 C 语言结构体。 + - **返回值**:返回 C 语言结构体表示的字段。 + +- `pub fn sql_repr(&self) -> String` + - **接口说明**:表示字段在 SQL 中的数据类型。 + - **返回值**:例如:"INT", "VARCHAR(100)" 等 SQL 数据类型表示。 + +### 参数绑定 +参数绑定功能主要由 Stmt 结构体支持。 +#### Stmt +Stmt 结构体提供了参数绑定相关功能,用于实现高效写入。 + +- `fn init(taos: &Q) -> RawResult` + - **接口说明**:初始化参数绑定实例。 + - **参数说明**: + - `taos`:数据库连接实例。 + - **返回值**:成功时返回初始化的实例,失败时返回错误。 + +- `fn init_with_req_id(taos: &Q, req_id: u64) -> RawResult` + - **接口说明**:使用请求ID初始化参数绑定实例。 + - **参数说明**: + - `taos`:数据库连接实例。 + - `req_id`:请求ID。 + - **返回值**:成功时返回初始化的实例,失败时返回错误。 + +- `fn prepare>(&mut self, sql: S) -> RawResult<&mut Self>` + - **接口说明**:准备要绑定的 SQL 语句。 + - **参数说明**: + - `sql`:要准备的SQL语句。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn set_tbname>(&mut self, name: S) -> RawResult<&mut Self>` + - **接口说明**:设置表名称。 + - **参数说明**: + - `name`:表名称。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn set_tags(&mut self, tags: &[Value]) -> RawResult<&mut Self>` + - **接口说明**:设置标签。 + - **参数说明**: + - `tags`:标签数组。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn set_tbname_tags>(&mut self, name: S, tags: &[Value]) -> RawResult<&mut Self>` + - **接口说明**:设置表名称和标签。 + - **参数说明**: + - `name`:表名称。 + - `tags`:标签数组。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn bind(&mut self, params: &[ColumnView]) -> RawResult<&mut Self>` + - **接口说明**:绑定参数。 + - **参数说明**: + - `params`:参数数组。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn add_batch(&mut self) -> RawResult<&mut Self>` + - **接口说明**:添加批处理。 + - **返回值**:成功时返回自身的可变引用,失败时返回错误。 + +- `fn execute(&mut self) -> RawResult` + - **接口说明**:执行语句。 + - **返回值**:成功时返回受影响的行数,失败时返回错误。 + +- `fn affected_rows(&self) -> usize` + - **接口说明**:获取受影响的行数。 + - **返回值**:受影响的行数。 + +### 数据订阅 +数据订阅主要涉及三个结构体,提供连接建立的 TmqBuilder, 消费数据和提交偏移量的 Consumer,以及偏移量 Offset。 + +#### TmqBuilder +同 TaosBuilder 类似,TmqBuilder 提供了创建消费者对象的功能。 + +- `fn available_params() -> &'static [&'static str]` + - **接口说明**:获取 DSN 中可用的参数列表。 + - **返回值**:返回静态字符串切片的引用,包含可用的参数名称。 + +- `fn from_dsn(dsn: D) -> RawResult` + - **接口说明**:使用 DSN 字符串创建连接,不检查连接。 + - **参数说明**: + - `dsn`:DSN 字符串或可转换为DSN的类型。 + - **返回值**:成功时返回自身类型的 `RawResult`,失败时返回错误。 + +- `fn client_version() -> &'static str` + - **接口说明**:获取客户端版本。 + - **返回值**:返回客户端版本的静态字符串。 + +- `fn ping(&self, conn: &mut Self::Target) -> RawResult<()>` + - **接口说明**:检查连接是否仍然存活。 + - **参数说明**: + - `conn`:目标连接的可变引用。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn ready(&self) -> bool` + - **接口说明**:检查是否准备好连接。 + - **返回值**:大多数情况下返回true,表示地址准备好连接。 + +- `fn build(&self) -> RawResult` + - **接口说明**:从此结构创建新的连接。 + - **返回值**:成功时返回目标连接类型的 `RawResult`,失败时返回错误。 + +#### Consumer +Consumer 结构体提供了订阅相关的功能,包括订阅,获取消息,提交偏移量,设置偏移量等。 + +- `fn subscribe, I: IntoIterator + Send>(&mut self, topics: I) -> RawResult<()>` + - **接口说明**:订阅一系列主题。 + - **参数说明**: + - `topics`:要订阅的主题列表。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn recv_timeout(&self, timeout: Timeout) -> RawResult)>>` + - **接口说明**:在指定超时时间内接收消息。 + - **参数说明**: + - `timeout`:超时时间。 + - **返回值**:成功时返回消息,失败时返回错误。 + +- `fn commit(&self, offset: Self::Offset) -> RawResult<()>` + - **接口说明**:提交给定的偏移量。 + - **参数说明**: + - `offset`:要提交的偏移量,见下文 Offset 结构体。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn commit_offset(&self, topic_name: &str, vgroup_id: VGroupId, offset: i64) -> RawResult<()>` + - **接口说明**:为特定主题和分区提交偏移量。 + - **参数说明**: + - `topic_name`:主题名称。 + - `vgroup_id`:分区 ID。 + - `offset`:要提交的偏移量。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn list_topics(&self) -> RawResult>` + - **接口说明**:列出所有可用主题。 + - **返回值**:成功时返回主题列表,失败时返回错误。 + +- `fn assignments(&self) -> Option)>>` + - **接口说明**:获取当前分配的主题和分区。 + - **返回值**:成功时返回分配信息,失败时返回 `None`。 + +- `fn offset_seek(&mut self, topic: &str, vg_id: VGroupId, offset: i64) -> RawResult<()>` + - **接口说明**:为特定主题和分区设置偏移量。 + - **参数说明**: + - `topic`:主题名称。 + - `vg_id`:分区 ID。 + - `offset`:要设置的偏移量。 + - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 + +- `fn committed(&self, topic: &str, vgroup_id: VGroupId) -> RawResult` + - **接口说明**:获取特定主题和分区的已提交偏移量。 + - **参数说明**: + - `topic`:主题名称。 + - `vgroup_id`:分区 ID。 + - **返回值**:成功时返回偏移量,失败时返回错误。 + +- `fn position(&self, topic: &str, vgroup_id: VGroupId) -> RawResult` + - **接口说明**:获取特定主题和分区的当前位置。 + - **参数说明**: + - `topic`:主题名称。 + - `vgroup_id`:分区 ID。 + - **返回值**:成功时返回当前位置,失败时返回错误。 + +#### Offset + +Offset 结构体提供了获取当前消息所属的数据库,主题和分区信息。 + +- `fn database(&self) -> &str` + - **接口说明**:获取当前消息的数据库名称。 + - **返回值**:数据库名称的引用。 + +- `fn topic(&self) -> &str` + - **接口说明**:获取当前消息的主题名称。 + - **返回值**:主题名称的引用。 + +- `fn vgroup_id(&self) -> VGroupId` + - **接口说明**:获取当前消息的分区 ID。 + - **返回值**:分区 ID。 + +其他相关结构体 API 使用说明请移步 Rust 文档托管网页:https://docs.rs/taos。 [taos]: https://github.com/taosdata/rust-connector-taos [deadpool]: https://crates.io/crates/deadpool From d92554ff508b7861bd30a67fe64a44a1cc9366a6 Mon Sep 17 00:00:00 2001 From: Yaming Pei Date: Fri, 2 Aug 2024 09:32:05 +0800 Subject: [PATCH 4/7] The Connector section of the official website reconstructs the C language interface description --- docs/examples/c/CCreateDBDemo.c | 76 +++++++++++++++++++++ docs/examples/c/CInsertDataDemo.c | 76 +++++++++++++++++++++ docs/examples/c/CQueryDataDemo.c | 82 +++++++++++++++++++++++ docs/examples/c/CWithReqIdDemo.c | 93 ++++++++++++++++++++++++++ docs/zh/08-develop/01-connect/index.md | 28 ++++++++ docs/zh/08-develop/02-sql.md | 16 +++++ 6 files changed, 371 insertions(+) create mode 100644 docs/examples/c/CCreateDBDemo.c create mode 100644 docs/examples/c/CInsertDataDemo.c create mode 100644 docs/examples/c/CQueryDataDemo.c create mode 100644 docs/examples/c/CWithReqIdDemo.c diff --git a/docs/examples/c/CCreateDBDemo.c b/docs/examples/c/CCreateDBDemo.c new file mode 100644 index 0000000000..cb655eb18d --- /dev/null +++ b/docs/examples/c/CCreateDBDemo.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o CCreateDBDemo CCreateDBDemo.c -ltaos + +#include +#include +#include +#include +#include "taos.h" + + +static int DemoCreateDB() { +// ANCHOR: create_db_and_table + int ret_code = -1; + const char *ip = "localhost"; + const char *user = "root"; + const char *password = "taosdata"; + + // connect + TAOS *taos = taos_connect(ip, user, password, NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason: %s\n", taos_errstr(NULL)); + goto end; + } + + // create database + TAOS_RES *result = taos_query(taos, "CREATE DATABASE IF NOT EXISTS power"); + int code = taos_errno(result); + if (code != 0) { + printf("failed to create database, reason: %s\n", taos_errstr(result)); + goto end; + } + taos_free_result(result); + printf("success to create database\n"); + + // use database + result = taos_query(taos, "USE power"); + taos_free_result(result); + + // create table + const char* sql = "CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; + result = taos_query(taos, sql); + code = taos_errno(result); + if (code != 0) { + printf("failed to create table, reason: %s\n", taos_errstr(result)); + goto end; + } + taos_free_result(result); + printf("success to create table\n"); + ret_code = 0; + +end: + // close & clean + taos_close(taos); + taos_cleanup(); + return ret_code; +// ANCHOR_END: create_db_and_table +} + +int main(int argc, char *argv[]) { + return DemoCreateDB(); +} diff --git a/docs/examples/c/CInsertDataDemo.c b/docs/examples/c/CInsertDataDemo.c new file mode 100644 index 0000000000..4ec228a6d5 --- /dev/null +++ b/docs/examples/c/CInsertDataDemo.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o CInsertDataDemo CInsertDataDemo.c -ltaos + +#include +#include +#include +#include +#include "taos.h" + +static int DemoInsertData() { +// ANCHOR: insert_data + int ret_code = -1; + const char *ip = "localhost"; + const char *user = "root"; + const char *password = "taosdata"; + + // connect + TAOS *taos = taos_connect(ip, user, password, NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason: %s\n", taos_errstr(NULL)); + goto end; + } + + // use database + TAOS_RES *result = taos_query(taos, "USE power"); + taos_free_result(result); + + // insert data, please make sure the database and table are already created + const char* sql = "INSERT INTO " \ + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " \ + "VALUES " \ + "(NOW + 1a, 10.30000, 219, 0.31000) " \ + "(NOW + 2a, 12.60000, 218, 0.33000) " \ + "(NOW + 3a, 12.30000, 221, 0.31000) " \ + "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " \ + "VALUES " \ + "(NOW + 1a, 10.30000, 218, 0.25000) "; + result = taos_query(taos, sql); + int code = taos_errno(result); + if (code != 0) { + printf("failed to insert rows, reason: %s\n", taos_errstr(result)); + goto end; + } + taos_free_result(result); + + // you can check affectedRows here + int rows = taos_affected_rows(result); + printf("success to insert %d rows\n", rows); + ret_code = 0; + +end: + // close & clean + taos_close(taos); + taos_cleanup(); + return ret_code; +// ANCHOR_END: insert_data +} + +int main(int argc, char *argv[]) { + return DemoInsertData(); +} diff --git a/docs/examples/c/CQueryDataDemo.c b/docs/examples/c/CQueryDataDemo.c new file mode 100644 index 0000000000..3b994dfae8 --- /dev/null +++ b/docs/examples/c/CQueryDataDemo.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o CQueryDataDemo CQueryDataDemo.c -ltaos + +#include +#include +#include +#include +#include "taos.h" + + +static int DemoQueryData() { +// ANCHOR: query_data + int ret_code = -1; + const char *ip = "localhost"; + const char *user = "root"; + const char *password = "taosdata"; + + // connect + TAOS *taos = taos_connect(ip, user, password, NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason: %s\n", taos_errstr(NULL)); + goto end; + } + + // use database + TAOS_RES *result = taos_query(taos, "USE power"); + taos_free_result(result); + + // query data, please make sure the database and table are already created + const char* sql = "SELECT * FROM power.meters"; + result = taos_query(taos, sql); + int code = taos_errno(result); + if (code != 0) { + printf("failed to select, reason: %s\n", taos_errstr(result)); + goto end; + } + + TAOS_ROW row = NULL; + int rows = 0; + int num_fields = taos_field_count(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + + printf("fields: %d\n", num_fields); + printf("sql: %s, result:\n", sql); + + // fetch the records row by row + while ((row = taos_fetch_row(result))) { + char temp[1024] = {0}; + rows++; + taos_print_row(temp, row, fields, num_fields); + printf("%s\n", temp); + } + printf("total rows: %d\n", rows); + taos_free_result(result); + ret_code = 0; + +end: + // close & clean + taos_close(taos); + taos_cleanup(); + return ret_code; +// ANCHOR_END: query_data +} + +int main(int argc, char *argv[]) { + return DemoQueryData(); +} diff --git a/docs/examples/c/CWithReqIdDemo.c b/docs/examples/c/CWithReqIdDemo.c new file mode 100644 index 0000000000..a2055d733b --- /dev/null +++ b/docs/examples/c/CWithReqIdDemo.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +// TAOS standard API example. The same syntax as MySQL, but only a subset +// to compile: gcc -o CWithReqIdDemo CWithReqIdDemo.c -ltaos + +#include +#include +#include +#include +#include "taos.h" + + +static int DemoWithReqId() { +// ANCHOR: with_reqid + int ret_code = -1; + const char *ip = "localhost"; + const char *user = "root"; + const char *password = "taosdata"; + + // connect + TAOS *taos = taos_connect(ip, user, password, NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason: %s\n", taos_errstr(NULL)); + goto end; + } + + // create database + TAOS_RES *result = taos_query_with_reqid(taos, "CREATE DATABASE IF NOT EXISTS power", 1L); + int code = taos_errno(result); + if (code != 0) { + printf("failed to create database, reason: %s\n", taos_errstr(result)); + taos_free_result(result); + goto end; + } + taos_free_result(result); + printf("success to create database\n"); + + // use database + result = taos_query_with_reqid(taos, "USE power", 2L); + taos_free_result(result); + + // query data + const char* sql = "SELECT * FROM power.meters"; + result = taos_query_with_reqid(taos, sql, 3L); + code = taos_errno(result); + if (code != 0) { + printf("failed to select, reason: %s\n", taos_errstr(result)); + goto end; + } + + TAOS_ROW row = NULL; + int rows = 0; + int num_fields = taos_field_count(result); + TAOS_FIELD *fields = taos_fetch_fields(result); + + printf("fields: %d\n", num_fields); + printf("sql: %s, result:\n", sql); + + // fetch the records row by row + while ((row = taos_fetch_row(result))) { + char temp[1024] = {0}; + rows++; + taos_print_row(temp, row, fields, num_fields); + printf("%s\n", temp); + } + printf("total rows: %d\n", rows); + taos_free_result(result); + ret_code = 0; + +end: + // close & clean + taos_close(taos); + taos_cleanup(); + return ret_code; +// ANCHOR_END: with_reqid +} + +int main(int argc, char *argv[]) { + return DemoWithReqId(); +} diff --git a/docs/zh/08-develop/01-connect/index.md b/docs/zh/08-develop/01-connect/index.md index fcb70f2293..3a47f41d00 100644 --- a/docs/zh/08-develop/01-connect/index.md +++ b/docs/zh/08-develop/01-connect/index.md @@ -337,6 +337,34 @@ properties 中的配置参数如下: +使用客户端驱动访问 TDengine 集群的基本过程为:建立连接、查询和写入、关闭连接、清除资源。 + +下面为建立连接的示例代码,其中省略了查询和写入部分,展示了如何建立连接、关闭连接以及清除资源。 + +```c + TAOS *taos = taos_connect("localhost:6030", "root", "taosdata", NULL, 0); + if (taos == NULL) { + printf("failed to connect to server, reason:%s\n", "null taos" /*taos_errstr(taos)*/); + exit(1); + } + + /* put your code here for read and write */ + + taos_close(taos); + taos_cleanup(); +``` + +在上面的示例代码中, `taos_connect()` 建立到客户端程序所在主机的 6030 端口的连接,`taos_close()`关闭当前连接,`taos_cleanup()`清除客户端驱动所申请和使用的资源。 + +:::note + +- 如未特别说明,当 API 的返回值是整数时,_0_ 代表成功,其它是代表失败原因的错误码,当返回值是指针时, _NULL_ 表示失败。 +- 所有的错误码以及对应的原因描述在 `taoserror.h` 文件中。 + +::: + + + diff --git a/docs/zh/08-develop/02-sql.md b/docs/zh/08-develop/02-sql.md index 4fef3c8659..2325becfdf 100644 --- a/docs/zh/08-develop/02-sql.md +++ b/docs/zh/08-develop/02-sql.md @@ -35,6 +35,10 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL +```c +{{#include docs/examples/c/CCreateDBDemo.c:create_db_and_table}} +``` +> **注意**:如果不使用 `USE power` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 power.meters。 @@ -65,6 +69,12 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```c +{{#include docs/examples/c/CInsertDataDemo.c:insert_data}} +``` + +**Note** +NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW + 1s 代表客户端当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒),s(秒),m(分),h(小时),d(天),w(周),n(月),y(年)。 @@ -95,6 +105,9 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```c +{{#include docs/examples/c/CQueryDataDemo.c:query_data}} +``` @@ -133,6 +146,9 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId +```c +{{#include docs/examples/c/CWithReqIdDemo.c:with_reqid}} +``` From 43a9872c4ca1f307c828930506a4f91b0974b829 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Fri, 2 Aug 2024 14:02:22 +0800 Subject: [PATCH 5/7] mod rust dev guide --- .../rust/nativeexample/examples/connect.rs | 4 +- .../rust/nativeexample/examples/query.rs | 100 +++++++++--------- .../rust/nativeexample/examples/schemaless.rs | 8 +- .../rust/nativeexample/examples/stmt.rs | 5 + .../rust/restexample/examples/connect.rs | 4 +- docs/zh/08-develop/01-connect/index.md | 51 ++++++++- docs/zh/08-develop/02-sql.md | 22 +++- docs/zh/08-develop/04-schemaless.md | 7 ++ docs/zh/08-develop/05-stmt.md | 6 +- docs/zh/08-develop/07-tmq.md | 9 +- docs/zh/14-reference/05-connector/26-rust.mdx | 98 +++++++++++------ 11 files changed, 212 insertions(+), 102 deletions(-) diff --git a/docs/examples/rust/nativeexample/examples/connect.rs b/docs/examples/rust/nativeexample/examples/connect.rs index fb226d8710..dee6db2a41 100644 --- a/docs/examples/rust/nativeexample/examples/connect.rs +++ b/docs/examples/rust/nativeexample/examples/connect.rs @@ -3,7 +3,7 @@ use taos::*; #[tokio::main] async fn main() -> Result<(), Error> { #[allow(unused_variables)] - let taos = TaosBuilder::from_dsn("taos://")?.build()?; - println!("Connected"); + let taos = TaosBuilder::from_dsn("taos://localhost:6030")?.build()?; + println!("Connected to localhost with native connection successfully."); Ok(()) } diff --git a/docs/examples/rust/nativeexample/examples/query.rs b/docs/examples/rust/nativeexample/examples/query.rs index dfe55e8749..a493e7c729 100644 --- a/docs/examples/rust/nativeexample/examples/query.rs +++ b/docs/examples/rust/nativeexample/examples/query.rs @@ -7,60 +7,62 @@ async fn main() -> anyhow::Result<()> { let taos = builder.build()?; - // ANCHOR: create_db_and_table - let db = "power"; - // create database - taos.exec_many([ - format!("DROP DATABASE IF EXISTS `{db}`"), - format!("CREATE DATABASE `{db}`"), - format!("USE `{db}`"), - ]) - .await?; +// ANCHOR: create_db_and_table +let db = "power"; +// create database +taos.exec_many([ + format!("CREATE DATABASE IF NOT EXISTS `{db}`"), + format!("USE `{db}`"), +]) +.await?; +println!("Create database power successfully."); - // create table - taos.exec_many([ - // create super table - "CREATE TABLE `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) \ - TAGS (`groupid` INT, `location` BINARY(24))", - ]).await?; - // ANCHOR_END: create_db_and_table - - // ANCHOR: insert_data - let inserted = taos.exec("INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(NOW + 1a, 10.30000, 219, 0.31000) " + - "(NOW + 2a, 12.60000, 218, 0.33000) " + - "(NOW + 3a, 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "(NOW + 1a, 10.30000, 218, 0.25000) ").await?; +// create super table +taos.exec_many([ + "CREATE TABLE `meters` (`ts` TIMESTAMP, `current` FLOAT, `voltage` INT, `phase` FLOAT) \ + TAGS (`groupid` INT, `location` BINARY(24))", +]).await?; +println!("Create stable meters successfully."); - println!("inserted: {} rows", inserted); - // ANCHOR_END: insert_data +// ANCHOR_END: create_db_and_table - // ANCHOR: query_data - let mut result = taos.query("SELECT * FROM power.meters").await?; +// ANCHOR: insert_data +let inserted = taos.exec("INSERT INTO " + +"power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + +"VALUES " + +"(NOW + 1a, 10.30000, 219, 0.31000) " + +"(NOW + 2a, 12.60000, 218, 0.33000) " + +"(NOW + 3a, 12.30000, 221, 0.31000) " + +"power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + +"VALUES " + +"(NOW + 1a, 10.30000, 218, 0.25000) ").await?; - for field in result.fields() { - println!("got field: {}", field.name()); +println!("inserted: {} rows to power.meters successfully.", inserted); +// ANCHOR_END: insert_data + +// ANCHOR: query_data +// query data, make sure the database and table are created before +let mut result = taos.query("SELECT ts, current, location FROM power.meters limit 100").await?; + +for field in result.fields() { + println!("got field: {}", field.name()); +} + +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 + ); } + nrows += 1; +} +// ANCHOR_END: query_data - 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 - ); - } - nrows += 1; - } - // ANCHOR_END: query_data - - // ANCHOR: query_with_req_id - let result = taos.query_with_req_id("SELECT * FROM power.meters", 0).await?; - // ANCHOR_END: query_with_req_id +// ANCHOR: query_with_req_id +let result = taos.query_with_req_id("SELECT ts, current, location FROM power.meters limit 1", 1).await?; +// ANCHOR_END: query_with_req_id } diff --git a/docs/examples/rust/nativeexample/examples/schemaless.rs b/docs/examples/rust/nativeexample/examples/schemaless.rs index 44ce0fe694..2da99400d3 100644 --- a/docs/examples/rust/nativeexample/examples/schemaless.rs +++ b/docs/examples/rust/nativeexample/examples/schemaless.rs @@ -17,8 +17,6 @@ async fn put() -> anyhow::Result<()> { let db = "power"; - client.exec(format!("drop database if exists {db}")).await?; - client .exec(format!("create database if not exists {db}")) .await?; @@ -44,7 +42,7 @@ async fn put() -> anyhow::Result<()> { // SchemalessProtocol::Telnet let data = [ - "meters.current 1648432611249 10.3 location=California.SanFrancisco group=2", + "metric_telnet 1648432611249 10.3 location=California.SanFrancisco group=2", ] .map(String::from) .to_vec(); @@ -60,7 +58,7 @@ async fn put() -> anyhow::Result<()> { // SchemalessProtocol::Json let data = [ - r#"[{"metric": "meters.current", "timestamp": 1681345954000, "value": 10.3, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, "tags": {"location": "California.LosAngeles", "groupid": 1}}, {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "California.LosAngeles", "groupid": 1}}]"# + r#"[{"metric": "metric_json", "timestamp": 1681345954000, "value": 10.3, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, "tags": {"location": "California.LosAngeles", "groupid": 1}}, {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "California.LosAngeles", "groupid": 1}}]"# ] .map(String::from) .to_vec(); @@ -74,7 +72,5 @@ async fn put() -> anyhow::Result<()> { .build()?; assert_eq!(client.put(&sml_data).await?, ()); - client.exec(format!("drop database if exists {db}")).await?; - Ok(()) } diff --git a/docs/examples/rust/nativeexample/examples/stmt.rs b/docs/examples/rust/nativeexample/examples/stmt.rs index 0194eccdf1..d784607e03 100644 --- a/docs/examples/rust/nativeexample/examples/stmt.rs +++ b/docs/examples/rust/nativeexample/examples/stmt.rs @@ -17,6 +17,8 @@ async fn main() -> anyhow::Result<()> { for i in 0..NUM_TABLES { let table_name = format!("d{}", i); let tags = vec![Value::VarChar("California.SanFransico".into()), Value::Int(2)]; + + // set table name and tags for the prepared statement. stmt.set_tbname_tags(&table_name, &tags).await?; for j in 0..NUM_ROWS { let values = vec![ @@ -25,13 +27,16 @@ async fn main() -> anyhow::Result<()> { ColumnView::from_ints(vec![219 + j as i32]), ColumnView::from_floats(vec![0.31 + j as f32]), ]; + // bind values to the prepared statement. stmt.bind(&values).await?; } + stmt.add_batch().await?; } // execute. let rows = stmt.execute().await?; assert_eq!(rows, NUM_TABLES * NUM_ROWS); + Ok(()) } diff --git a/docs/examples/rust/restexample/examples/connect.rs b/docs/examples/rust/restexample/examples/connect.rs index fb226d8710..0c89517f22 100644 --- a/docs/examples/rust/restexample/examples/connect.rs +++ b/docs/examples/rust/restexample/examples/connect.rs @@ -3,7 +3,7 @@ use taos::*; #[tokio::main] async fn main() -> Result<(), Error> { #[allow(unused_variables)] - let taos = TaosBuilder::from_dsn("taos://")?.build()?; - println!("Connected"); + let taos = TaosBuilder::from_dsn("taos+ws://localhost:6041")?.build()?; + println!("Connected to localhost with websocket connection successfully."); Ok(()) } diff --git a/docs/zh/08-develop/01-connect/index.md b/docs/zh/08-develop/01-connect/index.md index ac2787a4cc..bd738209f9 100644 --- a/docs/zh/08-develop/01-connect/index.md +++ b/docs/zh/08-develop/01-connect/index.md @@ -321,7 +321,7 @@ Java 连接器建立连接的参数有 URL 和 Properties。 TDengine 的 JDBC URL 规范格式为: `jdbc:[TAOS|TAOS-RS]://[host_name]:[port]/[database_name]?[user={user}|&password={password}|&charset={charset}|&cfgdir={config_dir}|&locale={locale}|&timezone={timezone}]` -URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../../reference/connector/java/#url-规范) +URL 和 Properties 的详细参数说明和如何使用详见 [url 规范](../../reference/connector/java/#url-规范)
@@ -329,6 +329,16 @@ URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../.. +Rust 连接器使用 DSN 来创建连接, DSN 描述字符串基本结构如下: + +```text +[+]://[[:@]:][/][?=[&=]] +|------|------------|---|-----------|-----------|------|------|------------|-----------------------| +|driver| protocol | | username | password | host | port | database | params | +``` + +DSN 的详细说明和如何使用详见 [连接功能](../../reference/connector/rust/#连接功能) + @@ -359,7 +369,9 @@ URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../.. - +```rust +{{#include docs/examples/rust/restexample/examples/connect.rs}} +``` ```js @@ -396,7 +408,10 @@ URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../.. - +```rust +{{#include docs/examples/rust/nativeexample/examples/connect.rs}} +``` + @@ -431,7 +446,7 @@ URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../.. - +不支持 @@ -491,7 +506,33 @@ URL 和 Properties 的详细参数说明和如何使用详见 [API 说明](../.. - + +在复杂应用中,建议启用连接池。[taos] 的连接池默认(异步模式)使用 [deadpool] 实现。 + +如下,可以生成一个默认参数的连接池。 + +```rust +let pool: Pool = TaosBuilder::from_dsn("taos:///") + .unwrap() + .pool() + .unwrap(); +``` + +同样可以使用连接池的构造器,对连接池参数进行设置: + +```rust +let pool: Pool = Pool::builder(Manager::from_dsn(self.dsn.clone()).unwrap().0) + .max_size(88) // 最大连接数 + .build() + .unwrap(); +``` + +在应用代码中,使用 `pool.get()?` 来获取一个连接对象 [Taos]。 + +```rust +let taos = pool.get()?; +``` + diff --git a/docs/zh/08-develop/02-sql.md b/docs/zh/08-develop/02-sql.md index 7b4c6e5d98..d4ee344c11 100644 --- a/docs/zh/08-develop/02-sql.md +++ b/docs/zh/08-develop/02-sql.md @@ -21,7 +21,6 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL ```java {{#include examples/JDBC/JDBCDemo/src/main/java/com/taosdata/example/JdbcCreatDBDemo.java:create_db_and_table}} ``` -> **注意**:如果不使用 `USE power` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 power.meters。 @@ -31,6 +30,11 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL + +```rust +{{#include docs/examples/rust/nativeexample/examples/query.rs:create_db_and_table}} +``` + @@ -41,6 +45,7 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL
+> **注意**:如果不使用 `USE power` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 `power.meters`。 ## 插入数据 下面以智能电表为例,展示如何使用连接器执行 SQL 来插入数据到 `power` 数据库的 `meters` 超级表。样例使用 TDengine 自动建表 SQL 语法,写入 d1001 子表中 3 条数据,写入 d1002 子表中 1 条数据,然后打印出实际插入数据条数。 @@ -61,6 +66,11 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW + +```rust +{{#include docs/examples/rust/nativeexample/examples/query.rs:insert_data}} +``` + @@ -90,6 +100,11 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW + +```rust +{{#include docs/examples/rust/nativeexample/examples/query.rs:query_data}} +``` + @@ -127,6 +142,11 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId + +```rust +{{#include docs/examples/rust/nativeexample/examples/query.rs:query_with_req_id}} +``` + diff --git a/docs/zh/08-develop/04-schemaless.md b/docs/zh/08-develop/04-schemaless.md index 734e9558a2..7a5730df46 100644 --- a/docs/zh/08-develop/04-schemaless.md +++ b/docs/zh/08-develop/04-schemaless.md @@ -181,6 +181,11 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO + +```rust +{{#include docs/examples/rust/restexample/examples/schemaless.rs}} +``` + @@ -211,6 +216,7 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO +除 DSN 不同,其余同 Websocket 代码示例。 @@ -234,6 +240,7 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO + 不支持 diff --git a/docs/zh/08-develop/05-stmt.md b/docs/zh/08-develop/05-stmt.md index 132a1b8850..5dd9daaed5 100644 --- a/docs/zh/08-develop/05-stmt.md +++ b/docs/zh/08-develop/05-stmt.md @@ -43,6 +43,10 @@ import TabItem from "@theme/TabItem";
+```rust +{{#include docs/examples/rust/restexample/examples/stmt.rs}} +``` + @@ -82,7 +86,7 @@ import TabItem from "@theme/TabItem"; - +除 DSN 不同,其余同 Websocket 代码示例。 diff --git a/docs/zh/08-develop/07-tmq.md b/docs/zh/08-develop/07-tmq.md index 1d5b59307e..405d227e8e 100644 --- a/docs/zh/08-develop/07-tmq.md +++ b/docs/zh/08-develop/07-tmq.md @@ -46,7 +46,7 @@ TDengine 消费者的概念跟 Kafka 类似,消费者通过订阅主题来接 下面是各语言连接器创建参数: -Java 连接器创建消费者的参数为 Properties, 可以设置的参数列表请参考 [API 说明](../../reference/connector/java/#消费者) +Java 连接器创建消费者的参数为 Properties, 可以设置的参数列表请参考 [消费者参数](../../reference/connector/java/#消费者) 其他参数请参考上文通用基础配置项。 @@ -58,6 +58,8 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 +Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请参考 [DSN](../../reference/connector/rust/#dsn) +其他参数请参考上文通用基础配置项。 @@ -102,6 +104,11 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 + +```rust +{{#include docs/examples/rust/nativeexample/examples/tmq.rs:create_consumer}} +``` + diff --git a/docs/zh/14-reference/05-connector/26-rust.mdx b/docs/zh/14-reference/05-connector/26-rust.mdx index f6c9e5d688..e33d3f0a0f 100644 --- a/docs/zh/14-reference/05-connector/26-rust.mdx +++ b/docs/zh/14-reference/05-connector/26-rust.mdx @@ -168,7 +168,7 @@ DSN 描述字符串基本结构如下: 各部分意义见下表: - **driver**: 必须指定驱动名以便连接器选择何种方式创建连接,支持如下驱动名: - - **taos**: 表名使用 TDengine 连接器驱动。 + - **taos**: 表明使用 TDengine 连接器驱动。 - **tmq**: 使用 TMQ 订阅数据。 - **http/ws**: 使用 Websocket 创建连接。 - **https/wss**: 在 Websocket 连接方式下显示启用 SSL/TLS 连接。 @@ -640,16 +640,16 @@ DSN 描述字符串基本结构如下: 一个完整的 DSN 描述字符串示例如下:`taos+ws://localhost:6041/test`, 表示使用 Websocket(`ws`)方式通过 `6041` 端口连接服务器 `localhost`,并指定默认数据库为 `test`。 #### TaosBuilder -TaosBuilder 结构体提供了建立连接,检查连接,以及获取服务端版本号等功能。 +TaosBuilder 结构体主要提供了根据 DSN 构建 Taos 对象的方法,还提供了检查连接,以及获取客户端版本号等功能。 - `fn available_params() -> &'static [&'static str]` - - **接口说明**:获取DSN中可用的参数列表。 + - **接口说明**:获取 DSN 中可用的参数列表。 - **返回值**:返回静态字符串切片的引用,包含可用的参数名称。 - `fn from_dsn(dsn: D) -> RawResult` - - **接口说明**:使用DSN字符串创建连接,不检查连接。 + - **接口说明**:使用 DSN 字符串创建连接,不检查连接。 - **参数说明**: - - `dsn`:DSN字符串或可转换为DSN的类型。 + - `dsn`:DSN 字符串或可转换为 DSN 的类型。 - **返回值**:成功时返回自身类型的 `RawResult`,失败时返回错误。 - `fn client_version() -> &'static str` @@ -664,14 +664,15 @@ TaosBuilder 结构体提供了建立连接,检查连接,以及获取服务 - `fn ready(&self) -> bool` - **接口说明**:检查是否准备好连接。 - - **返回值**:大多数情况下返回true,表示地址准备好连接。 + - **返回值**:大多数情况下返回 `true`,表示地址准备好连接。 - `fn build(&self) -> RawResult` - - **接口说明**:从此结构创建新的连接。 + - **接口说明**:从此结构创建新的 Taos 对象。 - **返回值**:成功时返回目标连接类型的 `RawResult`,失败时返回错误。 ### 执行 SQL -执行 SQL 主要涉及到 Taos 结构体,以及结果集 ResultSet 结构体,还有列信息 Field。 +执行 SQL 主要使用 Taos 结构体,获取结果集以及元数据需要使用下节介绍的 ResultSet 结构体 和列信息 Field 结构体。 + #### Taos Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无模式写入,以及一些常用数据库查询的封装(如创建数据库,获取) @@ -684,34 +685,34 @@ Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无 - **返回值**:如果使用websocket协议,则返回 `true`,否则返回 `false`。 - `fn query>(&self, sql: T) -> RawResult` - - **接口说明**:执行SQL查询。 + - **接口说明**:执行 SQL 查询。 - **参数说明**: - - `sql`:要执行的SQL语句。 + - `sql`:要执行的 SQL 语句。 - **返回值**:成功时返回结果集 `ResultSet` 的 `RawResult`,失败时返回错误。 - `fn query_with_req_id>(&self, sql: T, req_id: u64) -> RawResult` - - **接口说明**:带请求ID执行SQL查询。 + - **接口说明**:带请求 ID 执行 SQL 查询。 - **参数说明**: - - `sql`:要执行的SQL语句。 - - `req_id`:请求ID。 + - `sql`:要执行的 SQL 语句。 + - `req_id`:请求 ID。 - **返回值**:成功时返回结果集 `ResultSet` 的 `RawResult`,失败时返回错误。 - `fn exec>(&self, sql: T) -> RawResult` - - **接口说明**:执行SQL语句。 + - **接口说明**:执行 SQL 语句。 - **参数说明**: - - `sql`:要执行的SQL语句。 + - `sql`:要执行的 SQL 语句。 - **返回值**:成功时返回受影响的行数,失败时返回错误。 - `fn exec_many, I: IntoIterator>(&self, input: I) -> RawResult` - - **接口说明**:批量执行SQL语句。 + - **接口说明**:批量执行 SQL 语句。 - **参数说明**: - - `input`:要执行的SQL语句集合。 + - `input`:要执行的 SQL 语句集合。 - **返回值**:成功时返回总共受影响的行数,失败时返回错误。 - `fn query_one, O: DeserializeOwned>(&self, sql: T) -> RawResult>` - - **接口说明**:执行SQL查询并返回单个结果。 + - **接口说明**:执行 SQL 查询并返回单个结果。 - **参数说明**: - - `sql`:要执行的SQL语句。 + - `sql`:要执行的 SQL 语句。 - **返回值**:成功时返回可选的结果对象,失败时返回错误。 - `fn server_version(&self) -> RawResult>` @@ -722,7 +723,7 @@ Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无 - **接口说明**:创建主题。 - **参数说明**: - `name`:主题名称。 - - `sql`:关联的SQL语句。 + - `sql`:关联的 SQ L语句。 - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 - `fn databases(&self) -> RawResult>` @@ -737,7 +738,7 @@ Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无 - **接口说明**:描述表结构。 - **参数说明**: - `table`:表名称。 - - **返回值**:成功时返回表描述的 `RawResult`,失败时返回错误。 + - **返回值**:成功时返回表结构描述的 `RawResult`,失败时返回错误。 - `fn database_exists(&self, name: &str) -> RawResult` - **接口说明**:检查数据库是否存在。 @@ -746,12 +747,43 @@ Taos 结构体提供了多个数据库操作的 API,包括:执行 SQL,无 - **返回值**:成功时返回布尔值的 `RawResult`,指示数据库是否存在,失败时返回错误。 - `fn put(&self, data: &SmlData) -> RawResult<()>` - - **接口说明**:写入无模式数据。 + - **接口说明**:写入无模式数据,SmlData 结构介绍见下文。 - **参数说明**: - `data`:无模式数据。 - **返回值**:成功时返回空的 `RawResult`,失败时返回错误。 +### SmlData +SmlData 结构体提供了无模式写入的数据结构,以及获取属性的方法。 +- `pub struct SmlData` + - **结构体说明**:`SmlData` 结构体用于存储无模式数据及其相关信息。 + - **字段说明**: + - `protocol`:无模式协议,支持 `Line`, `Telnet`, `Json`, 三种。 + - `precision`:时间戳精度,支持 `Hours`, `Minutes`, `Seconds`, `Millisecond`(默认), `Microsecond`, `Nanosecond`。 + - `data`:数据列表。 + - `ttl`:数据存活时间,单位为秒。 + - `req_id`:请求 ID。 +- `pub fn protocol(&self) -> SchemalessProtocol` + - **接口说明**:获取无模式协议。 + - **返回值**:无模式协议类型,支持 `Line`, `Telnet`, `Json`, 三种。 + +- `pub fn precision(&self) -> SchemalessPrecision` + - **接口说明**:获取时间戳精度。 + - **返回值**:时间戳精度类型,支持 `Hours`, `Minutes`, `Seconds`, `Millisecond`(默认), `Microsecond`, `Nanosecond`。 + +- `pub fn data(&self) -> &Vec` + - **接口说明**:获取数据列表。 + - **返回值**:数据列表的引用。 + +- `pub fn ttl(&self) -> Option` + - **接口说明**:获取数据存活时间。 + - **返回值**:数据存活时间(可选),单位为秒。 + +- `pub fn req_id(&self) -> Option` + - **接口说明**:获取请求 ID。 + - **返回值**:请求 ID(可选)。 + +### 结果获取 #### ResultSet ResultSet 结构体提供了结果集的一些方法,可以用来获取结果集的数据和元数据。 @@ -844,16 +876,16 @@ Stmt 结构体提供了参数绑定相关功能,用于实现高效写入。 - **返回值**:成功时返回初始化的实例,失败时返回错误。 - `fn init_with_req_id(taos: &Q, req_id: u64) -> RawResult` - - **接口说明**:使用请求ID初始化参数绑定实例。 + - **接口说明**:使用请求 ID 初始化参数绑定实例。 - **参数说明**: - `taos`:数据库连接实例。 - - `req_id`:请求ID。 + - `req_id`:请求 ID。 - **返回值**:成功时返回初始化的实例,失败时返回错误。 - `fn prepare>(&mut self, sql: S) -> RawResult<&mut Self>` - **接口说明**:准备要绑定的 SQL 语句。 - **参数说明**: - - `sql`:要准备的SQL语句。 + - `sql`:要准备的 SQL 语句。 - **返回值**:成功时返回自身的可变引用,失败时返回错误。 - `fn set_tbname>(&mut self, name: S) -> RawResult<&mut Self>` @@ -921,7 +953,7 @@ Stmt 结构体提供了参数绑定相关功能,用于实现高效写入。 - `fn ready(&self) -> bool` - **接口说明**:检查是否准备好连接。 - - **返回值**:大多数情况下返回true,表示地址准备好连接。 + - **返回值**:大多数情况下返回 `true`,表示地址准备好连接。 - `fn build(&self) -> RawResult` - **接口说明**:从此结构创建新的连接。 @@ -1002,12 +1034,8 @@ Offset 结构体提供了获取当前消息所属的数据库,主题和分区 - **接口说明**:获取当前消息的分区 ID。 - **返回值**:分区 ID。 -其他相关结构体 API 使用说明请移步 Rust 文档托管网页:https://docs.rs/taos。 - -[taos]: https://github.com/taosdata/rust-connector-taos -[deadpool]: https://crates.io/crates/deadpool -[r2d2]: https://crates.io/crates/r2d2 -[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 +## 附录 +- Rust 连接器文档:https://docs.rs/taos +- Rust 连接器项目地址: https://github.com/taosdata/rust-connector-taos +- deadpool 连接池: https://crates.io/crates/deadpool +- r2d2 连接池: https://crates.io/crates/r2d2 From 1bb29caf50c1388726d11cf40cd13112678900c4 Mon Sep 17 00:00:00 2001 From: sheyanjie-qq <249478495@qq.com> Date: Fri, 2 Aug 2024 14:05:14 +0800 Subject: [PATCH 6/7] mod schemaless --- .../rust/restexample/examples/schemaless.rs | 76 ++++++++ .../rust/restexample/examples/stmt.rs | 42 +++++ .../examples/rust/restexample/examples/tmq.rs | 163 ++++++++++++++++++ docs/zh/08-develop/04-schemaless.md | 2 +- 4 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 docs/examples/rust/restexample/examples/schemaless.rs create mode 100644 docs/examples/rust/restexample/examples/stmt.rs create mode 100644 docs/examples/rust/restexample/examples/tmq.rs diff --git a/docs/examples/rust/restexample/examples/schemaless.rs b/docs/examples/rust/restexample/examples/schemaless.rs new file mode 100644 index 0000000000..eefcd63dae --- /dev/null +++ b/docs/examples/rust/restexample/examples/schemaless.rs @@ -0,0 +1,76 @@ +use taos_query::common::SchemalessPrecision; +use taos_query::common::SchemalessProtocol; +use taos_query::common::SmlDataBuilder; + +use crate::AsyncQueryable; +use crate::AsyncTBuilder; +use crate::TaosBuilder; + +async fn put() -> anyhow::Result<()> { + std::env::set_var("RUST_LOG", "taos=debug"); + pretty_env_logger::init(); + let dsn = + std::env::var("TDENGINE_ClOUD_DSN").unwrap_or("https://localhost:6041".to_string()); + log::debug!("dsn: {:?}", &dsn); + + let client = TaosBuilder::from_dsn(dsn)?.build().await?; + + let db = "power"; + + client + .exec(format!("create database if not exists {db}")) + .await?; + + // should specify database before insert + client.exec(format!("use {db}")).await?; + + // SchemalessProtocol::Line + let data = [ + "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639000000", + ] + .map(String::from) + .to_vec(); + + let sml_data = SmlDataBuilder::default() + .protocol(SchemalessProtocol::Line) + .precision(SchemalessPrecision::Millisecond) + .data(data.clone()) + .ttl(1000) + .req_id(100u64) + .build()?; + assert_eq!(client.put(&sml_data).await?, ()); + + // SchemalessProtocol::Telnet + let data = [ + "metric_telnet 1648432611249 10.3 location=California.SanFrancisco group=2", + ] + .map(String::from) + .to_vec(); + + let sml_data = SmlDataBuilder::default() + .protocol(SchemalessProtocol::Telnet) + .precision(SchemalessPrecision::Millisecond) + .data(data.clone()) + .ttl(1000) + .req_id(200u64) + .build()?; + assert_eq!(client.put(&sml_data).await?, ()); + + // SchemalessProtocol::Json + let data = [ + r#"[{"metric": "metric_json", "timestamp": 1681345954000, "value": 10.3, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, "tags": {"location": "California.LosAngeles", "groupid": 1}}, {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, "tags": {"location": "California.SanFrancisco", "groupid": 2}}, {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "California.LosAngeles", "groupid": 1}}]"# + ] + .map(String::from) + .to_vec(); + + let sml_data = SmlDataBuilder::default() + .protocol(SchemalessProtocol::Json) + .precision(SchemalessPrecision::Millisecond) + .data(data.clone()) + .ttl(1000) + .req_id(300u64) + .build()?; + assert_eq!(client.put(&sml_data).await?, ()); + + Ok(()) +} diff --git a/docs/examples/rust/restexample/examples/stmt.rs b/docs/examples/rust/restexample/examples/stmt.rs new file mode 100644 index 0000000000..524b37b919 --- /dev/null +++ b/docs/examples/rust/restexample/examples/stmt.rs @@ -0,0 +1,42 @@ +use taos::*; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + let taos = TaosBuilder::from_dsn("ws://")?.build().await?; + + taos.exec("DROP DATABASE IF EXISTS power").await?; + taos.create_database("power").await?; + taos.use_database("power").await?; + taos.exec("CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)").await?; + + let mut stmt = Stmt::init(&taos).await?; + stmt.prepare("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)").await?; + + const NUM_TABLES: usize = 10; + const NUM_ROWS: usize = 10; + for i in 0..NUM_TABLES { + let table_name = format!("d{}", i); + let tags = vec![Value::VarChar("California.SanFransico".into()), Value::Int(2)]; + + // set table name and tags for the prepared statement. + stmt.set_tbname_tags(&table_name, &tags).await?; + for j in 0..NUM_ROWS { + let values = vec![ + ColumnView::from_millis_timestamp(vec![1648432611249 + j as i64]), + ColumnView::from_floats(vec![10.3 + j as f32]), + ColumnView::from_ints(vec![219 + j as i32]), + ColumnView::from_floats(vec![0.31 + j as f32]), + ]; + // bind values to the prepared statement. + stmt.bind(&values).await?; + } + + stmt.add_batch().await?; + } + + // execute. + let rows = stmt.execute().await?; + assert_eq!(rows, NUM_TABLES * NUM_ROWS); + + Ok(()) +} diff --git a/docs/examples/rust/restexample/examples/tmq.rs b/docs/examples/rust/restexample/examples/tmq.rs new file mode 100644 index 0000000000..8f195e1629 --- /dev/null +++ b/docs/examples/rust/restexample/examples/tmq.rs @@ -0,0 +1,163 @@ +use std::time::Duration; +use std::str::FromStr; + +use taos::*; + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + pretty_env_logger::formatted_timed_builder() + .filter_level(log::LevelFilter::Info) + .init(); + use taos_query::prelude::*; + let dsn = "ws://localhost:6041".to_string(); + log::info!("dsn: {}", dsn); + let mut dsn = Dsn::from_str(&dsn)?; + + let taos = TaosBuilder::from_dsn(&dsn)?.build().await?; + + // prepare database and table + taos.exec_many([ + "drop topic if exists topic_meters", + "drop database if exists power", + "create database if not exists power WAL_RETENTION_PERIOD 86400", + "use power", + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))", + "create table if not exists power.d001 using power.meters tags(1,'location')", + ]) + .await?; + + taos.exec_many([ + "drop database if exists db2", + "create database if not exists db2 wal_retention_period 3600", + "use db2", + ]) + .await?; + + // ANCHOR: create_topic + taos.exec_many([ + "CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM power.meters", + ]) + .await?; + // ANCHOR_END: create_topic + + // ANCHOR: create_consumer + dsn.params.insert("group.id".to_string(), "abc".to_string()); + dsn.params.insert("auto.offset.reset".to_string(), "earliest".to_string()); + + let builder = TmqBuilder::from_dsn(&dsn)?; + let mut consumer = builder.build().await?; + // ANCHOR_END: create_consumer + + // ANCHOR: subscribe + consumer.subscribe(["topic_meters"]).await?; + // ANCHOR_END: subscribe + + // ANCHOR: consume + { + let mut stream = consumer.stream_with_timeout(Timeout::from_secs(1)); + + while let Some((offset, message)) = stream.try_next().await? { + + let topic: &str = offset.topic(); + let database = offset.database(); + let vgroup_id = offset.vgroup_id(); + log::debug!( + "topic: {}, database: {}, vgroup_id: {}", + topic, + database, + vgroup_id + ); + + match message { + MessageSet::Meta(meta) => { + log::info!("Meta"); + let raw = meta.as_raw_meta().await?; + taos.write_raw_meta(&raw).await?; + + let json = meta.as_json_meta().await?; + let sql = json.to_string(); + if let Err(err) = taos.exec(sql).await { + println!("maybe error: {}", err); + } + } + MessageSet::Data(data) => { + log::info!("Data"); + while let Some(data) = data.fetch_raw_block().await? { + log::debug!("data: {:?}", data); + } + } + MessageSet::MetaData(meta, data) => { + log::info!("MetaData"); + let raw = meta.as_raw_meta().await?; + taos.write_raw_meta(&raw).await?; + + let json = meta.as_json_meta().await?; + let sql = json.to_string(); + if let Err(err) = taos.exec(sql).await { + println!("maybe error: {}", err); + } + + while let Some(data) = data.fetch_raw_block().await? { + log::debug!("data: {:?}", data); + } + } + } + consumer.commit(offset).await?; + } + } + // ANCHOR_END: consume + + // ANCHOR: assignments + let assignments = consumer.assignments().await.unwrap(); + log::info!("assignments: {:?}", assignments); + // ANCHOR_END: assignments + + // seek offset + for topic_vec_assignment in assignments { + let topic = &topic_vec_assignment.0; + let vec_assignment = topic_vec_assignment.1; + for assignment in vec_assignment { + let vgroup_id = assignment.vgroup_id(); + let current = assignment.current_offset(); + let begin = assignment.begin(); + let end = assignment.end(); + log::debug!( + "topic: {}, vgroup_id: {}, current offset: {} begin {}, end: {}", + topic, + vgroup_id, + current, + begin, + end + ); + // ANCHOR: seek_offset + let res = consumer.offset_seek(topic, vgroup_id, end).await; + if res.is_err() { + log::error!("seek offset error: {:?}", res); + let a = consumer.assignments().await.unwrap(); + log::error!("assignments: {:?}", a); + } + // ANCHOR_END: seek_offset + } + + let topic_assignment = consumer.topic_assignment(topic).await; + log::debug!("topic assignment: {:?}", topic_assignment); + } + + // after seek offset + let assignments = consumer.assignments().await.unwrap(); + log::info!("after seek offset assignments: {:?}", assignments); + + // ANCHOR: unsubscribe + consumer.unsubscribe().await; + // ANCHOR_END: unsubscribe + + tokio::time::sleep(Duration::from_secs(1)).await; + + taos.exec_many([ + "drop database db2", + "drop topic topic_meters", + "drop database power", + ]) + .await?; + Ok(()) +} diff --git a/docs/zh/08-develop/04-schemaless.md b/docs/zh/08-develop/04-schemaless.md index 7a5730df46..9c136cb109 100644 --- a/docs/zh/08-develop/04-schemaless.md +++ b/docs/zh/08-develop/04-schemaless.md @@ -161,7 +161,7 @@ st,t1=3,t2=4,t3=t3 c1=3i64,c6="passit" 1626006833640000000 ### Websocket 连接 - + ```java From 251d9ecab1bcbfb1ca5da0c520ea7e793b96a925 Mon Sep 17 00:00:00 2001 From: t_max <1172915550@qq.com> Date: Fri, 2 Aug 2024 14:28:24 +0800 Subject: [PATCH 7/7] docs: add go and csharp example --- docs/en/07-develop/01-connect/index.md | 2 +- docs/examples/csharp/connect/Program.cs | 28 +- docs/examples/csharp/csharp.sln | 18 + docs/examples/csharp/nativesml/Program.cs | 57 + .../csharp/nativesml/nativesml.csproj | 13 + .../obj/nativesml.csproj.nuget.dgspec.json | 67 + .../obj/nativesml.csproj.nuget.g.props | 15 + .../obj/nativesml.csproj.nuget.g.targets | 2 + .../csharp/nativesml/obj/project.assets.json | 149 +++ .../csharp/nativesml/obj/project.nuget.cache | 11 + .../nativesml/obj/project.packagespec.json | 1 + .../obj/rider.project.model.nuget.info | 1 + .../nativesml/obj/rider.project.restore.info | 1 + docs/examples/csharp/optsJSON/Program.cs | 55 +- docs/examples/csharp/query/Program.cs | 3 +- docs/examples/csharp/sqlInsert/Program.cs | 145 ++- docs/examples/csharp/stmtInsert/Program.cs | 74 +- docs/examples/csharp/subscribe/Program.cs | 243 +++- docs/examples/csharp/wsConnect/Program.cs | 28 +- docs/examples/csharp/wsInsert/Program.cs | 181 ++- docs/examples/csharp/wsQuery/Program.cs | 3 +- docs/examples/csharp/wsStmt/Program.cs | 76 +- docs/examples/csharp/wssml/Program.cs | 57 + .../csharp/wssml/obj/project.assets.json | 149 +++ .../csharp/wssml/obj/project.nuget.cache | 11 + .../csharp/wssml/obj/project.packagespec.json | 1 + .../wssml/obj/rider.project.model.nuget.info | 1 + .../wssml/obj/rider.project.restore.info | 1 + .../wssml/obj/wssml.csproj.nuget.dgspec.json | 67 + .../wssml/obj/wssml.csproj.nuget.g.props | 15 + .../wssml/obj/wssml.csproj.nuget.g.targets | 2 + docs/examples/csharp/wssml/wssml.csproj | 12 + docs/examples/csharp/wssubscribe/Program.cs | 229 ++++ .../wssubscribe/obj/project.assets.json | 150 +++ .../wssubscribe/obj/project.nuget.cache | 11 + .../wssubscribe/obj/project.packagespec.json | 1 + .../obj/rider.project.model.nuget.info | 1 + .../obj/rider.project.restore.info | 1 + .../obj/wssubscribe.csproj.nuget.dgspec.json | 68 + .../obj/wssubscribe.csproj.nuget.g.props | 18 + .../obj/wssubscribe.csproj.nuget.g.targets | 2 + .../csharp/wssubscribe/wssubscribe.csproj | 12 + docs/examples/go/connect/afconn/main.go | 2 +- docs/examples/go/connect/cgoexample/main.go | 7 +- docs/examples/go/connect/connpool/main.go | 33 + docs/examples/go/connect/restexample/main.go | 7 +- docs/examples/go/connect/wsexample/main.go | 23 + docs/examples/go/go.mod | 9 +- docs/examples/go/go.sum | 12 +- docs/examples/go/queryreqid/main.go | 55 + docs/examples/go/schemaless/native/main.go | 41 + docs/examples/go/schemaless/ws/main.go | 57 + docs/examples/go/sqlquery/main.go | 88 ++ docs/examples/go/stmt/native/main.go | 82 ++ docs/examples/go/stmt/ws/main.go | 102 ++ docs/examples/go/tmq/native/main.go | 132 ++ docs/examples/go/tmq/ws/main.go | 137 ++ docs/zh/08-develop/01-connect/index.md | 139 +- docs/zh/08-develop/02-sql.md | 80 ++ docs/zh/08-develop/04-schemaless.md | 43 +- docs/zh/08-develop/05-stmt.md | 16 +- docs/zh/08-develop/07-tmq.md | 121 +- docs/zh/14-reference/05-connector/20-go.mdx | 310 +---- .../14-reference/05-connector/40-csharp.mdx | 1158 +---------------- 64 files changed, 2928 insertions(+), 1708 deletions(-) create mode 100644 docs/examples/csharp/nativesml/Program.cs create mode 100644 docs/examples/csharp/nativesml/nativesml.csproj create mode 100644 docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.dgspec.json create mode 100644 docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.props create mode 100644 docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.targets create mode 100644 docs/examples/csharp/nativesml/obj/project.assets.json create mode 100644 docs/examples/csharp/nativesml/obj/project.nuget.cache create mode 100644 docs/examples/csharp/nativesml/obj/project.packagespec.json create mode 100644 docs/examples/csharp/nativesml/obj/rider.project.model.nuget.info create mode 100644 docs/examples/csharp/nativesml/obj/rider.project.restore.info create mode 100644 docs/examples/csharp/wssml/Program.cs create mode 100644 docs/examples/csharp/wssml/obj/project.assets.json create mode 100644 docs/examples/csharp/wssml/obj/project.nuget.cache create mode 100644 docs/examples/csharp/wssml/obj/project.packagespec.json create mode 100644 docs/examples/csharp/wssml/obj/rider.project.model.nuget.info create mode 100644 docs/examples/csharp/wssml/obj/rider.project.restore.info create mode 100644 docs/examples/csharp/wssml/obj/wssml.csproj.nuget.dgspec.json create mode 100644 docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.props create mode 100644 docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.targets create mode 100644 docs/examples/csharp/wssml/wssml.csproj create mode 100644 docs/examples/csharp/wssubscribe/Program.cs create mode 100644 docs/examples/csharp/wssubscribe/obj/project.assets.json create mode 100644 docs/examples/csharp/wssubscribe/obj/project.nuget.cache create mode 100644 docs/examples/csharp/wssubscribe/obj/project.packagespec.json create mode 100644 docs/examples/csharp/wssubscribe/obj/rider.project.model.nuget.info create mode 100644 docs/examples/csharp/wssubscribe/obj/rider.project.restore.info create mode 100644 docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.dgspec.json create mode 100644 docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.props create mode 100644 docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.targets create mode 100644 docs/examples/csharp/wssubscribe/wssubscribe.csproj create mode 100644 docs/examples/go/connect/connpool/main.go create mode 100644 docs/examples/go/connect/wsexample/main.go create mode 100644 docs/examples/go/queryreqid/main.go create mode 100644 docs/examples/go/schemaless/native/main.go create mode 100644 docs/examples/go/schemaless/ws/main.go create mode 100644 docs/examples/go/sqlquery/main.go create mode 100644 docs/examples/go/stmt/native/main.go create mode 100644 docs/examples/go/stmt/ws/main.go create mode 100644 docs/examples/go/tmq/native/main.go create mode 100644 docs/examples/go/tmq/ws/main.go diff --git a/docs/en/07-develop/01-connect/index.md b/docs/en/07-develop/01-connect/index.md index ec3ed7b6dd..90b63d96e3 100644 --- a/docs/en/07-develop/01-connect/index.md +++ b/docs/en/07-develop/01-connect/index.md @@ -172,7 +172,7 @@ npm install @tdengine/rest Just need to add the reference to [TDengine.Connector](https://www.nuget.org/packages/TDengine.Connector/) in the project configuration file. -```xml title=csharp.csproj {12} +```xml title=csharp.csproj diff --git a/docs/examples/csharp/connect/Program.cs b/docs/examples/csharp/connect/Program.cs index 0152b61b03..697871573c 100644 --- a/docs/examples/csharp/connect/Program.cs +++ b/docs/examples/csharp/connect/Program.cs @@ -3,16 +3,34 @@ using TDengine.Driver.Client; namespace TDengineExample { - internal class ConnectExample { + // ANCHOR: main static void Main(String[] args) { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + try { - Console.WriteLine("connected"); + // Connect to TDengine server using Native + var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); + // Open connection with using block, it will close the connection automatically + using (var client = DbDriver.Open(builder)) + { + Console.WriteLine("connected"); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; } } + // ANCHOR_END: main } -} +} \ No newline at end of file diff --git a/docs/examples/csharp/csharp.sln b/docs/examples/csharp/csharp.sln index 59c198b4c9..3e8074122c 100644 --- a/docs/examples/csharp/csharp.sln +++ b/docs/examples/csharp/csharp.sln @@ -27,6 +27,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wsStmt", "wsStmt\wsStmt.csp EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "sqlinsert", "sqlInsert\sqlinsert.csproj", "{CD24BD12-8550-4627-A11D-707B446F48C3}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "nativesml", "nativesml\nativesml.csproj", "{18ADDBE8-B266-4A66-8CC5-CFF80B530EFD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wssml", "wssml\wssml.csproj", "{C3E62FDB-CCBC-4F72-ACF6-D3B2C39630E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "wssubscribe", "wssubscribe\wssubscribe.csproj", "{CB4BCBA5-C758-433F-8B90-7389F59E46BD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -84,5 +90,17 @@ Global {CD24BD12-8550-4627-A11D-707B446F48C3}.Debug|Any CPU.Build.0 = Debug|Any CPU {CD24BD12-8550-4627-A11D-707B446F48C3}.Release|Any CPU.ActiveCfg = Release|Any CPU {CD24BD12-8550-4627-A11D-707B446F48C3}.Release|Any CPU.Build.0 = Release|Any CPU + {18ADDBE8-B266-4A66-8CC5-CFF80B530EFD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18ADDBE8-B266-4A66-8CC5-CFF80B530EFD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18ADDBE8-B266-4A66-8CC5-CFF80B530EFD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18ADDBE8-B266-4A66-8CC5-CFF80B530EFD}.Release|Any CPU.Build.0 = Release|Any CPU + {C3E62FDB-CCBC-4F72-ACF6-D3B2C39630E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3E62FDB-CCBC-4F72-ACF6-D3B2C39630E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3E62FDB-CCBC-4F72-ACF6-D3B2C39630E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3E62FDB-CCBC-4F72-ACF6-D3B2C39630E3}.Release|Any CPU.Build.0 = Release|Any CPU + {CB4BCBA5-C758-433F-8B90-7389F59E46BD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CB4BCBA5-C758-433F-8B90-7389F59E46BD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CB4BCBA5-C758-433F-8B90-7389F59E46BD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CB4BCBA5-C758-433F-8B90-7389F59E46BD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/docs/examples/csharp/nativesml/Program.cs b/docs/examples/csharp/nativesml/Program.cs new file mode 100644 index 0000000000..c4925041a1 --- /dev/null +++ b/docs/examples/csharp/nativesml/Program.cs @@ -0,0 +1,57 @@ +using TDengine.Driver; +using TDengine.Driver.Client; + +namespace TDengineExample +{ + internal class NativeSMLExample + { + // ANCHOR: main + public static void Main(string[] args) + { + var host = "127.0.0.1"; + + var lineDemo = + "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639"; + + var telnetDemo = "metric_telnet 1707095283260 4 host=host0 interface=eth0"; + + var jsonDemo = + "{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; + try + { + var builder = + new ConnectionStringBuilder( + $"host={host};port=6030;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) + { + // create database + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + // use database + client.Exec("USE power"); + // insert influx line protocol data + client.SchemalessInsert(new[]{lineDemo}, TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert opentsdb telnet protocol data + client.SchemalessInsert(new[]{telnetDemo}, TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert json data + client.SchemalessInsert(new []{jsonDemo}, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NOT_CONFIGURED, 0, ReqId.GetReqId()); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + // ANCHOR_END: main + } +} \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/nativesml.csproj b/docs/examples/csharp/nativesml/nativesml.csproj new file mode 100644 index 0000000000..afad009614 --- /dev/null +++ b/docs/examples/csharp/nativesml/nativesml.csproj @@ -0,0 +1,13 @@ + + + + Exe + net6.0 + enable + enable + + + + + + diff --git a/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.dgspec.json b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.dgspec.json new file mode 100644 index 0000000000..74b8259305 --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.dgspec.json @@ -0,0 +1,67 @@ +{ + "format": 1, + "restore": { + "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj": {} + }, + "projects": { + "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj", + "projectName": "nativesml", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.props b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.props new file mode 100644 index 0000000000..a270b60d2c --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /root/.nuget/packages/ + /root/.nuget/packages/ + PackageReference + 6.8.0 + + + + + \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.targets b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.targets new file mode 100644 index 0000000000..35a7576c5a --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/nativesml.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/project.assets.json b/docs/examples/csharp/nativesml/obj/project.assets.json new file mode 100644 index 0000000000..652bbd6688 --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/project.assets.json @@ -0,0 +1,149 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "TDengine.Connector/3.1.3": { + "type": "package", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/net6.0/TDengine.dll": {} + }, + "runtime": { + "lib/net6.0/TDengine.dll": {} + } + } + } + }, + "libraries": { + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "TDengine.Connector/3.1.3": { + "sha512": "dDX+Oex4I0X9yCalU0/YyUN0ecy+8X5xj6N8CoqeLrU6ICYDZgilSGQK9Fh3qmLobhGQvOJWwDpoO73rryHU5Q==", + "type": "package", + "path": "tdengine.connector/3.1.3", + "files": [ + ".nupkg.metadata", + "docs/README.md", + "image/logo.jpg", + "lib/net45/TDengine.dll", + "lib/net451/TDengine.dll", + "lib/net5.0/TDengine.dll", + "lib/net6.0/TDengine.dll", + "lib/netstandard2.0/TDengine.dll", + "lib/netstandard2.1/TDengine.dll", + "tdengine.connector.3.1.3.nupkg.sha512", + "tdengine.connector.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "TDengine.Connector >= 3.1.*" + ] + }, + "packageFolders": { + "/root/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj", + "projectName": "nativesml", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/project.nuget.cache b/docs/examples/csharp/nativesml/obj/project.nuget.cache new file mode 100644 index 0000000000..3c34e78160 --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/project.nuget.cache @@ -0,0 +1,11 @@ +{ + "version": 2, + "dgSpecHash": "xbVzGVQru/qLTE5UBOQoTSR5C+6GFj/M4fcB1h/3W6PsWOVoFQLbV4fwAAKt5f5BKxrV1phiwzm2zGYK0fpXBQ==", + "success": true, + "projectFilePath": "/mnt/e/github/TDengine/docs/examples/csharp/nativesml/nativesml.csproj", + "expectedPackageFiles": [ + "/root/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/root/.nuget/packages/tdengine.connector/3.1.3/tdengine.connector.3.1.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/project.packagespec.json b/docs/examples/csharp/nativesml/obj/project.packagespec.json new file mode 100644 index 0000000000..8c110899d3 --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"E:\\github\\TDengine\\docs\\examples\\csharp\\nativesml\\nativesml.csproj","projectName":"nativesml","projectPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\nativesml\\nativesml.csproj","outputPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\nativesml\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"E:\\github\\taos-connector-dotnet\\src\\resource":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","dependencies":{"TDengine.Connector":{"target":"Package","version":"[3.1.*, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\8.0.202\\RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/rider.project.model.nuget.info b/docs/examples/csharp/nativesml/obj/rider.project.model.nuget.info new file mode 100644 index 0000000000..c922ea143f --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17225691407520754 \ No newline at end of file diff --git a/docs/examples/csharp/nativesml/obj/rider.project.restore.info b/docs/examples/csharp/nativesml/obj/rider.project.restore.info new file mode 100644 index 0000000000..7559664705 --- /dev/null +++ b/docs/examples/csharp/nativesml/obj/rider.project.restore.info @@ -0,0 +1 @@ +17225689181017775 \ No newline at end of file diff --git a/docs/examples/csharp/optsJSON/Program.cs b/docs/examples/csharp/optsJSON/Program.cs index a93c4dad0f..747d89c0d3 100644 --- a/docs/examples/csharp/optsJSON/Program.cs +++ b/docs/examples/csharp/optsJSON/Program.cs @@ -7,22 +7,51 @@ namespace TDengineExample { public static void Main(string[] args) { - var builder = - new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + // ANCHOR: main + var host = "127.0.0.1"; + + var lineDemo = + "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639"; + + var telnetDemo = "metric_telnet 1707095283260 4 host=host0 interface=eth0"; + + var jsonDemo = + "{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; + try { - client.Exec("CREATE DATABASE test WAL_RETENTION_PERIOD 3600"); - client.Exec("use test"); - string[] lines = + var builder = + new ConnectionStringBuilder( + $"protocol=WebSocket;host={host};port=6041;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - "[{\"metric\": \"meters.current\", \"timestamp\": 1648432611249, \"value\": 10.3, \"tags\": {\"location\": \"California.SanFrancisco\", \"groupid\": 2}}," + - " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611249, \"value\": 219, \"tags\": {\"location\": \"California.LosAngeles\", \"groupid\": 1}}, " + - "{\"metric\": \"meters.current\", \"timestamp\": 1648432611250, \"value\": 12.6, \"tags\": {\"location\": \"California.SanFrancisco\", \"groupid\": 2}}," + - " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611250, \"value\": 221, \"tags\": {\"location\": \"California.LosAngeles\", \"groupid\": 1}}]" - }; - client.SchemalessInsert(lines, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // create database + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + // use database + client.Exec("USE power"); + // insert influx line protocol data + client.SchemalessInsert(new[]{lineDemo}, TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert opentsdb telnet protocol data + client.SchemalessInsert(new[]{telnetDemo}, TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert json data + client.SchemalessInsert(new []{jsonDemo}, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NOT_CONFIGURED, 0, ReqId.GetReqId()); + } } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: main } } } \ No newline at end of file diff --git a/docs/examples/csharp/query/Program.cs b/docs/examples/csharp/query/Program.cs index 4c354d9a5e..c901760f52 100644 --- a/docs/examples/csharp/query/Program.cs +++ b/docs/examples/csharp/query/Program.cs @@ -13,8 +13,7 @@ namespace TDengineExample { try { - client.Exec("use power"); - string query = "SELECT * FROM meters"; + string query = "SELECT * FROM power.meters"; using (var rows = client.Query(query)) { while (rows.Read()) diff --git a/docs/examples/csharp/sqlInsert/Program.cs b/docs/examples/csharp/sqlInsert/Program.cs index c3c700aba2..0ac8d55c5e 100644 --- a/docs/examples/csharp/sqlInsert/Program.cs +++ b/docs/examples/csharp/sqlInsert/Program.cs @@ -6,42 +6,125 @@ namespace TDengineExample { internal class SQLInsertExample { - public static void Main(string[] args) { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + try { - try + + var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; + CreateDatabaseAndTable(client); + InsertData(client); + QueryData(client); } } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + + private static void CreateDatabaseAndTable(ITDengineClient client) + { + // ANCHOR: create_db_and_table + try + { + // create database + var affected = client.Exec("CREATE DATABASE IF NOT EXISTS power"); + Console.WriteLine($"Create database power, affected rows: {affected}"); + // create table + affected = client.Exec( + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + Console.WriteLine($"Create table meters, affected rows: {affected}"); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: create_db_and_table + } + + private static void InsertData(ITDengineClient client) + { + // ANCHOR: insert_data + try + { + // insert data + var insertQuery = "INSERT INTO " + + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 219, 0.31000) " + + "(NOW + 2a, 12.60000, 218, 0.33000) " + + "(NOW + 3a, 12.30000, 221, 0.31000) " + + "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 218, 0.25000) "; + var affectedRows = client.Exec(insertQuery); + Console.WriteLine("inserted into " + affectedRows + " rows to power.meters successfully."); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: insert_data + } + + private static void QueryData(ITDengineClient client) + { + // ANCHOR: query_data + try + { + // query data + var query = "SELECT ts, current, location FROM power.meters limit 100"; + using (var rows = client.Query(query)) + { + while (rows.Read()) + { + var ts = (DateTime)rows.GetValue(0); + var current = (float)rows.GetValue(1); + var location = Encoding.UTF8.GetString((byte[])rows.GetValue(2)); + Console.WriteLine($"ts: {ts:yyyy-MM-dd HH:mm:ss.fff}, current: {current}, location: {location}"); + } + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: query_data } } -} +} \ No newline at end of file diff --git a/docs/examples/csharp/stmtInsert/Program.cs b/docs/examples/csharp/stmtInsert/Program.cs index e6b11a63e4..5b4cf2677c 100644 --- a/docs/examples/csharp/stmtInsert/Program.cs +++ b/docs/examples/csharp/stmtInsert/Program.cs @@ -5,34 +5,72 @@ namespace TDengineExample { internal class StmtInsertExample { + // ANCHOR: main public static void Main(string[] args) { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + var host = "127.0.0.1"; + var numOfSubTable = 10; + var numOfRow = 10; + var random = new Random(); + try { - try + var builder = new ConnectionStringBuilder($"host={host};port=6030;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - client.Exec($"create database power"); + // create database + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + // use database + client.Exec("USE power"); + // create table client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + "CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); using (var stmt = client.StmtInit()) { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); + String sql = "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)"; + stmt.Prepare(sql); + for (int i = 1; i <= numOfSubTable; i++) + { + var tableName = $"d_bind_{i}"; + // set table name + stmt.SetTableName(tableName); + // set tags + stmt.SetTags(new object[] { i, $"location_{i}" }); + var current = DateTime.Now; + // bind rows + for (int j = 0; j < numOfRow; j++) + { + stmt.BindRow(new object[] + { + current.Add(TimeSpan.FromMilliseconds(j)), + random.NextSingle() * 30, + random.Next(300), + random.NextSingle() + }); + } + // add batch + stmt.AddBatch(); + // execute + stmt.Exec(); + // get affected rows + var affectedRows = stmt.Affected(); + Console.WriteLine($"table {tableName} insert {affectedRows} rows."); + } } } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; } } + // ANCHOR_END: main } } \ No newline at end of file diff --git a/docs/examples/csharp/subscribe/Program.cs b/docs/examples/csharp/subscribe/Program.cs index d7c1a52117..80e25f1acf 100644 --- a/docs/examples/csharp/subscribe/Program.cs +++ b/docs/examples/csharp/subscribe/Program.cs @@ -1,5 +1,4 @@ - -using TDengine.Driver; +using TDengine.Driver; using TDengine.Driver.Client; using TDengine.TMQ; @@ -9,65 +8,221 @@ namespace TMQExample { public static void Main(string[] args) { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + try { - try + var builder = new ConnectionStringBuilder("host=127.0.0.1;port=6030;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - client.Exec("CREATE DATABASE power"); + client.Exec("CREATE DATABASE IF NOT EXISTS power"); client.Exec("USE power"); client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + client.Exec("CREATE TOPIC IF NOT EXISTS topic_meters as SELECT * from power.meters"); + var consumer = CreateConsumer(); + // insert data Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; + // consume message + Consume(consumer); + // seek + Seek(consumer); + // commit + CommitOffset(consumer); + // close + Close(consumer); + Console.WriteLine("Done"); } } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } } static void InsertData() { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); + var builder = new ConnectionStringBuilder("host=127.0.0.1;port=6030;username=root;password=taosdata"); using (var client = DbDriver.Open(builder)) { while (true) { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); + client.Exec( + "INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); Task.Delay(1000).Wait(); } } } - } -} + static IConsumer> CreateConsumer() + { + // ANCHOR: create_consumer + // consumer config + var cfg = new Dictionary() + { + { "td.connect.port", "6030" }, + { "auto.offset.reset", "latest" }, + { "msg.with.table.name", "true" }, + { "enable.auto.commit", "true" }, + { "auto.commit.interval.ms", "1000" }, + { "group.id", "group2" }, + { "client.id", "1" }, + { "td.connect.ip", "127.0.0.1" }, + { "td.connect.user", "root" }, + { "td.connect.pass", "taosdata" }, + }; + IConsumer> consumer = null!; + try + { + // create consumer + consumer = new ConsumerBuilder>(cfg).Build(); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + + // ANCHOR_END: create_consumer + return consumer; + } + + static void Consume(IConsumer> consumer) + { + // ANCHOR: subscribe + try + { + // subscribe + consumer.Subscribe(new List() { "topic_meters" }); + for (int i = 0; i < 50; i++) + { + // consume message with using block to ensure the result is disposed + using (var cr = consumer.Consume(100)) + { + if (cr == null) continue; + foreach (var message in cr.Message) + { + // handle message + Console.WriteLine( + $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + + $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); + } + } + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: subscribe + } + + static void Seek(IConsumer> consumer) + { + // ANCHOR: seek + try + { + // get assignment + var assignment = consumer.Assignment; + // seek to the beginning + foreach (var topicPartition in assignment) + { + consumer.Seek(new TopicPartitionOffset(topicPartition.Topic, topicPartition.Partition, 0)); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: seek + } + + static void CommitOffset(IConsumer> consumer) + { + // ANCHOR: commit_offset + for (int i = 0; i < 5; i++) + { + try + { + // consume message with using block to ensure the result is disposed + using (var cr = consumer.Consume(100)) + { + if (cr == null) continue; + // commit offset + consumer.Commit(new List + { + cr.TopicPartitionOffset, + }); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + // ANCHOR_END: commit_offset + } + + static void Close(IConsumer> consumer) + { + // ANCHOR: close + try + { + // unsubscribe + consumer.Unsubscribe(); + // close consumer + consumer.Close(); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: close + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wsConnect/Program.cs b/docs/examples/csharp/wsConnect/Program.cs index edf0eb31e6..c7423969d8 100644 --- a/docs/examples/csharp/wsConnect/Program.cs +++ b/docs/examples/csharp/wsConnect/Program.cs @@ -6,13 +6,33 @@ namespace Examples { public class WSConnExample { + // ANCHOR: main static void Main(string[] args) { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + try { - Console.WriteLine("connected"); + // Connect to TDengine server using WebSocket + var builder = new ConnectionStringBuilder( + "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); + // Open connection with using block, it will close the connection automatically + using (var client = DbDriver.Open(builder)) + { + Console.WriteLine("connected"); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; } } + // ANCHOR_END: main } -} +} \ No newline at end of file diff --git a/docs/examples/csharp/wsInsert/Program.cs b/docs/examples/csharp/wsInsert/Program.cs index 73136477e7..d393b775ba 100644 --- a/docs/examples/csharp/wsInsert/Program.cs +++ b/docs/examples/csharp/wsInsert/Program.cs @@ -1,4 +1,5 @@ using System; +using System.Text; using TDengine.Driver; using TDengine.Driver.Client; @@ -8,39 +9,159 @@ namespace Examples { public static void Main(string[] args) { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + try { - try + var builder = new ConnectionStringBuilder("protocol=WebSocket;host=127.0.0.1;port=6041;useSSL=false;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; + CreateDatabaseAndTable(client); + InsertData(client); + QueryData(client); + QueryWithReqId(client); } } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + + private static void CreateDatabaseAndTable(ITDengineClient client) + { + // ANCHOR: create_db_and_table + try + { + // create database + var affected = client.Exec("CREATE DATABASE IF NOT EXISTS power"); + Console.WriteLine($"Create database power, affected rows: {affected}"); + // create table + affected = client.Exec( + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + Console.WriteLine($"Create table meters, affected rows: {affected}"); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: create_db_and_table + } + + private static void InsertData(ITDengineClient client) + { + // ANCHOR: insert_data + try + { + // insert data + var insertQuery = "INSERT INTO " + + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 219, 0.31000) " + + "(NOW + 2a, 12.60000, 218, 0.33000) " + + "(NOW + 3a, 12.30000, 221, 0.31000) " + + "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 218, 0.25000) "; + var affectedRows = client.Exec(insertQuery); + Console.WriteLine("inserted " + affectedRows + " rows to power.meters successfully."); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: insert_data + } + + private static void QueryData(ITDengineClient client) + { + // ANCHOR: select_data + try + { + // query data + var query = "SELECT ts, current, location FROM power.meters limit 100"; + using (var rows = client.Query(query)) + { + while (rows.Read()) + { + var ts = (DateTime)rows.GetValue(0); + var current = (float)rows.GetValue(1); + var location = Encoding.UTF8.GetString((byte[])rows.GetValue(2)); + Console.WriteLine( + $"ts: {ts:yyyy-MM-dd HH:mm:ss.fff}, current: {current}, location: {location}"); + } + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: select_data + } + + private static void QueryWithReqId(ITDengineClient client) + { + // ANCHOR: query_id + try + { + // query data + var query = "SELECT ts, current, location FROM power.meters limit 1"; + // query with request id 1 + using (var rows = client.Query(query,1)) + { + while (rows.Read()) + { + var ts = (DateTime)rows.GetValue(0); + var current = (float)rows.GetValue(1); + var location = Encoding.UTF8.GetString((byte[])rows.GetValue(2)); + Console.WriteLine( + $"ts: {ts:yyyy-MM-dd HH:mm:ss.fff}, current: {current}, location: {location}"); + } + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: query_id } } -} +} \ No newline at end of file diff --git a/docs/examples/csharp/wsQuery/Program.cs b/docs/examples/csharp/wsQuery/Program.cs index 40aac24597..c58f23626c 100644 --- a/docs/examples/csharp/wsQuery/Program.cs +++ b/docs/examples/csharp/wsQuery/Program.cs @@ -14,8 +14,7 @@ namespace Examples { try { - client.Exec("use power"); - string query = "SELECT * FROM meters"; + string query = "SELECT * FROM power.meters"; using (var rows = client.Query(query)) { while (rows.Read()) diff --git a/docs/examples/csharp/wsStmt/Program.cs b/docs/examples/csharp/wsStmt/Program.cs index 5166dfea92..dfc98d17d6 100644 --- a/docs/examples/csharp/wsStmt/Program.cs +++ b/docs/examples/csharp/wsStmt/Program.cs @@ -6,36 +6,72 @@ namespace Examples { public class WSStmtExample { + // ANCHOR: main public static void Main(string[] args) { - var builder = - new ConnectionStringBuilder( - "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) + var host = "127.0.0.1"; + var numOfSubTable = 10; + var numOfRow = 10; + var random = new Random(); + try { - try + var builder = new ConnectionStringBuilder($"protocol=WebSocket;host={host};port=6041;useSSL=false;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) { - client.Exec($"create database power"); + // create database + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + // use database + client.Exec("USE power"); + // create table client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + "CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); using (var stmt = client.StmtInit()) { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); + String sql = "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)"; + stmt.Prepare(sql); + for (int i = 1; i <= numOfSubTable; i++) + { + var tableName = $"d_bind_{i}"; + // set table name + stmt.SetTableName(tableName); + // set tags + stmt.SetTags(new object[] { i, $"location_{i}" }); + var current = DateTime.Now; + // bind rows + for (int j = 0; j < numOfRow; j++) + { + stmt.BindRow(new object[] + { + current.Add(TimeSpan.FromMilliseconds(j)), + random.NextSingle() * 30, + random.Next(300), + random.NextSingle() + }); + } + // add batch + stmt.AddBatch(); + // execute + stmt.Exec(); + // get affected rows + var affectedRows = stmt.Affected(); + Console.WriteLine($"table {tableName} insert {affectedRows} rows."); + } } } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; } } + // ANCHOR_END: main } } \ No newline at end of file diff --git a/docs/examples/csharp/wssml/Program.cs b/docs/examples/csharp/wssml/Program.cs new file mode 100644 index 0000000000..5c47c6651b --- /dev/null +++ b/docs/examples/csharp/wssml/Program.cs @@ -0,0 +1,57 @@ +using TDengine.Driver; +using TDengine.Driver.Client; + +namespace TDengineExample +{ + internal class WssmlExample + { + // ANCHOR: main + public static void Main(string[] args) + { + var host = "127.0.0.1"; + + var lineDemo = + "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639"; + + var telnetDemo = "metric_telnet 1707095283260 4 host=host0 interface=eth0"; + + var jsonDemo = + "{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; + try + { + var builder = + new ConnectionStringBuilder( + $"protocol=WebSocket;host={host};port=6041;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) + { + // create database + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + // use database + client.Exec("USE power"); + // insert influx line protocol data + client.SchemalessInsert(new[]{lineDemo}, TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert opentsdb telnet protocol data + client.SchemalessInsert(new[]{telnetDemo}, TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); + // insert json data + client.SchemalessInsert(new []{jsonDemo}, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, + TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NOT_CONFIGURED, 0, ReqId.GetReqId()); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + // ANCHOR_END: main + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/project.assets.json b/docs/examples/csharp/wssml/obj/project.assets.json new file mode 100644 index 0000000000..a3062a28a9 --- /dev/null +++ b/docs/examples/csharp/wssml/obj/project.assets.json @@ -0,0 +1,149 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "TDengine.Connector/3.1.3": { + "type": "package", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/net6.0/TDengine.dll": {} + }, + "runtime": { + "lib/net6.0/TDengine.dll": {} + } + } + } + }, + "libraries": { + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "TDengine.Connector/3.1.3": { + "sha512": "dDX+Oex4I0X9yCalU0/YyUN0ecy+8X5xj6N8CoqeLrU6ICYDZgilSGQK9Fh3qmLobhGQvOJWwDpoO73rryHU5Q==", + "type": "package", + "path": "tdengine.connector/3.1.3", + "files": [ + ".nupkg.metadata", + "docs/README.md", + "image/logo.jpg", + "lib/net45/TDengine.dll", + "lib/net451/TDengine.dll", + "lib/net5.0/TDengine.dll", + "lib/net6.0/TDengine.dll", + "lib/netstandard2.0/TDengine.dll", + "lib/netstandard2.1/TDengine.dll", + "tdengine.connector.3.1.3.nupkg.sha512", + "tdengine.connector.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "TDengine.Connector >= 3.1.*" + ] + }, + "packageFolders": { + "/root/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj", + "projectName": "wssml", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/project.nuget.cache b/docs/examples/csharp/wssml/obj/project.nuget.cache new file mode 100644 index 0000000000..140c7e62da --- /dev/null +++ b/docs/examples/csharp/wssml/obj/project.nuget.cache @@ -0,0 +1,11 @@ +{ + "version": 2, + "dgSpecHash": "f/iAhsDLFU7jI95wf6NFa1XHue7HQsgzzqr1jqfMTnrejkprbps/2toSr4j9kUyRUVdJNr7/TtdHhEsxEhKo+A==", + "success": true, + "projectFilePath": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj", + "expectedPackageFiles": [ + "/root/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/root/.nuget/packages/tdengine.connector/3.1.3/tdengine.connector.3.1.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/project.packagespec.json b/docs/examples/csharp/wssml/obj/project.packagespec.json new file mode 100644 index 0000000000..587dbcda23 --- /dev/null +++ b/docs/examples/csharp/wssml/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssml\\wssml.csproj","projectName":"wssml","projectPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssml\\wssml.csproj","outputPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssml\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"E:\\github\\taos-connector-dotnet\\src\\resource":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","dependencies":{"TDengine.Connector":{"target":"Package","version":"[3.1.*, )"}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\8.0.202\\RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/rider.project.model.nuget.info b/docs/examples/csharp/wssml/obj/rider.project.model.nuget.info new file mode 100644 index 0000000000..8c12f7e019 --- /dev/null +++ b/docs/examples/csharp/wssml/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17225691310239873 \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/rider.project.restore.info b/docs/examples/csharp/wssml/obj/rider.project.restore.info new file mode 100644 index 0000000000..b11c9dec26 --- /dev/null +++ b/docs/examples/csharp/wssml/obj/rider.project.restore.info @@ -0,0 +1 @@ +17225689180359712 \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.dgspec.json b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.dgspec.json new file mode 100644 index 0000000000..314b2831c6 --- /dev/null +++ b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.dgspec.json @@ -0,0 +1,67 @@ +{ + "format": 1, + "restore": { + "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj": {} + }, + "projects": { + "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj", + "projectName": "wssml", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/wssml.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssml/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.props b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.props new file mode 100644 index 0000000000..a270b60d2c --- /dev/null +++ b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /root/.nuget/packages/ + /root/.nuget/packages/ + PackageReference + 6.8.0 + + + + + \ No newline at end of file diff --git a/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.targets b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.targets new file mode 100644 index 0000000000..35a7576c5a --- /dev/null +++ b/docs/examples/csharp/wssml/obj/wssml.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/examples/csharp/wssml/wssml.csproj b/docs/examples/csharp/wssml/wssml.csproj new file mode 100644 index 0000000000..0b8df205bb --- /dev/null +++ b/docs/examples/csharp/wssml/wssml.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + enable + enable + + + + + diff --git a/docs/examples/csharp/wssubscribe/Program.cs b/docs/examples/csharp/wssubscribe/Program.cs new file mode 100644 index 0000000000..269fc4c732 --- /dev/null +++ b/docs/examples/csharp/wssubscribe/Program.cs @@ -0,0 +1,229 @@ +using TDengine.Driver; +using TDengine.Driver.Client; +using TDengine.TMQ; + +namespace TMQExample +{ + internal class SubscribeDemo + { + public static void Main(string[] args) + { + try + { + var builder = new ConnectionStringBuilder("protocol=WebSocket;host=127.0.0.1;port=6041;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) + { + client.Exec("CREATE DATABASE IF NOT EXISTS power"); + client.Exec("USE power"); + client.Exec( + "CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); + client.Exec("CREATE TOPIC IF NOT EXISTS topic_meters as SELECT * from power.meters"); + var consumer = CreateConsumer(); + // insert data + Task.Run(InsertData); + // consume message + Consume(consumer); + // seek + Seek(consumer); + // commit + CommitOffset(consumer); + // close + Close(consumer); + Console.WriteLine("Done"); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + + static void InsertData() + { + var builder = new ConnectionStringBuilder("protocol=WebSocket;host=127.0.0.1;port=6041;username=root;password=taosdata"); + using (var client = DbDriver.Open(builder)) + { + while (true) + { + client.Exec( + "INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); + Task.Delay(1000).Wait(); + } + } + } + + static IConsumer> CreateConsumer() + { + // ANCHOR: create_consumer + // consumer config + var cfg = new Dictionary() + { + {"td.connect.type", "WebSocket"}, + { "td.connect.port", "6041" }, + { "auto.offset.reset", "latest" }, + { "msg.with.table.name", "true" }, + { "enable.auto.commit", "true" }, + { "auto.commit.interval.ms", "1000" }, + { "group.id", "group2" }, + { "client.id", "1" }, + { "td.connect.ip", "127.0.0.1" }, + { "td.connect.user", "root" }, + { "td.connect.pass", "taosdata" }, + }; + IConsumer> consumer = null!; + try + { + // create consumer + consumer = new ConsumerBuilder>(cfg).Build(); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + + // ANCHOR_END: create_consumer + return consumer; + } + + static void Consume(IConsumer> consumer) + { + // ANCHOR: subscribe + try + { + // subscribe + consumer.Subscribe(new List() { "topic_meters" }); + for (int i = 0; i < 50; i++) + { + // consume message with using block to ensure the result is disposed + using (var cr = consumer.Consume(100)) + { + if (cr == null) continue; + foreach (var message in cr.Message) + { + // handle message + Console.WriteLine( + $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + + $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); + } + } + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: subscribe + } + + static void Seek(IConsumer> consumer) + { + // ANCHOR: seek + try + { + // get assignment + var assignment = consumer.Assignment; + // seek to the beginning + foreach (var topicPartition in assignment) + { + consumer.Seek(new TopicPartitionOffset(topicPartition.Topic, topicPartition.Partition, 0)); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: seek + } + + static void CommitOffset(IConsumer> consumer) + { + // ANCHOR: commit_offset + for (int i = 0; i < 5; i++) + { + try + { + // consume message with using block to ensure the result is disposed + using (var cr = consumer.Consume(100)) + { + if (cr == null) continue; + // commit offset + consumer.Commit(new List + { + cr.TopicPartitionOffset, + }); + } + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + } + // ANCHOR_END: commit_offset + } + + static void Close(IConsumer> consumer) + { + // ANCHOR: close + try + { + // unsubscribe + consumer.Unsubscribe(); + // close consumer + consumer.Close(); + } + catch (TDengineError e) + { + // handle TDengine error + Console.WriteLine(e.Message); + throw; + } + catch (Exception e) + { + // handle other exceptions + Console.WriteLine(e.Message); + throw; + } + // ANCHOR_END: close + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/project.assets.json b/docs/examples/csharp/wssubscribe/obj/project.assets.json new file mode 100644 index 0000000000..8335d20e65 --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/project.assets.json @@ -0,0 +1,150 @@ +{ + "version": 3, + "targets": { + "net6.0": { + "Newtonsoft.Json/13.0.3": { + "type": "package", + "compile": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net6.0/Newtonsoft.Json.dll": { + "related": ".xml" + } + } + }, + "TDengine.Connector/3.1.3": { + "type": "package", + "dependencies": { + "Newtonsoft.Json": "13.0.3" + }, + "compile": { + "lib/net6.0/TDengine.dll": {} + }, + "runtime": { + "lib/net6.0/TDengine.dll": {} + } + } + } + }, + "libraries": { + "Newtonsoft.Json/13.0.3": { + "sha512": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==", + "type": "package", + "path": "newtonsoft.json/13.0.3", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "LICENSE.md", + "README.md", + "lib/net20/Newtonsoft.Json.dll", + "lib/net20/Newtonsoft.Json.xml", + "lib/net35/Newtonsoft.Json.dll", + "lib/net35/Newtonsoft.Json.xml", + "lib/net40/Newtonsoft.Json.dll", + "lib/net40/Newtonsoft.Json.xml", + "lib/net45/Newtonsoft.Json.dll", + "lib/net45/Newtonsoft.Json.xml", + "lib/net6.0/Newtonsoft.Json.dll", + "lib/net6.0/Newtonsoft.Json.xml", + "lib/netstandard1.0/Newtonsoft.Json.dll", + "lib/netstandard1.0/Newtonsoft.Json.xml", + "lib/netstandard1.3/Newtonsoft.Json.dll", + "lib/netstandard1.3/Newtonsoft.Json.xml", + "lib/netstandard2.0/Newtonsoft.Json.dll", + "lib/netstandard2.0/Newtonsoft.Json.xml", + "newtonsoft.json.13.0.3.nupkg.sha512", + "newtonsoft.json.nuspec", + "packageIcon.png" + ] + }, + "TDengine.Connector/3.1.3": { + "sha512": "dDX+Oex4I0X9yCalU0/YyUN0ecy+8X5xj6N8CoqeLrU6ICYDZgilSGQK9Fh3qmLobhGQvOJWwDpoO73rryHU5Q==", + "type": "package", + "path": "tdengine.connector/3.1.3", + "files": [ + ".nupkg.metadata", + "docs/README.md", + "image/logo.jpg", + "lib/net45/TDengine.dll", + "lib/net451/TDengine.dll", + "lib/net5.0/TDengine.dll", + "lib/net6.0/TDengine.dll", + "lib/netstandard2.0/TDengine.dll", + "lib/netstandard2.1/TDengine.dll", + "tdengine.connector.3.1.3.nupkg.sha512", + "tdengine.connector.nuspec" + ] + } + }, + "projectFileDependencyGroups": { + "net6.0": [ + "TDengine.Connector >= 3.1.*" + ] + }, + "packageFolders": { + "/root/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj", + "projectName": "wssubscribe", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )", + "generatePathProperty": true + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/project.nuget.cache b/docs/examples/csharp/wssubscribe/obj/project.nuget.cache new file mode 100644 index 0000000000..07a2d75f6b --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/project.nuget.cache @@ -0,0 +1,11 @@ +{ + "version": 2, + "dgSpecHash": "iYS3B811DdocWqUXN2aMJdEwvfDVCixB5mK4XYN+98yFFNdPOU8hN4wQCxaOSFM7xKpvlmJvQPwkMetGBbFO8g==", + "success": true, + "projectFilePath": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj", + "expectedPackageFiles": [ + "/root/.nuget/packages/newtonsoft.json/13.0.3/newtonsoft.json.13.0.3.nupkg.sha512", + "/root/.nuget/packages/tdengine.connector/3.1.3/tdengine.connector.3.1.3.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/project.packagespec.json b/docs/examples/csharp/wssubscribe/obj/project.packagespec.json new file mode 100644 index 0000000000..319dd58c7f --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssubscribe\\wssubscribe.csproj","projectName":"wssubscribe","projectPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssubscribe\\wssubscribe.csproj","outputPath":"E:\\github\\TDengine\\docs\\examples\\csharp\\wssubscribe\\obj\\","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\":{},"E:\\github\\taos-connector-dotnet\\src\\resource":{},"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","dependencies":{"TDengine.Connector":{"target":"Package","version":"[3.1.*, )","generatePathProperty":true}},"imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"C:\\Program Files\\dotnet\\sdk\\8.0.202\\RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/rider.project.model.nuget.info b/docs/examples/csharp/wssubscribe/obj/rider.project.model.nuget.info new file mode 100644 index 0000000000..4a9bcd784b --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/rider.project.model.nuget.info @@ -0,0 +1 @@ +17225691490262111 \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/rider.project.restore.info b/docs/examples/csharp/wssubscribe/obj/rider.project.restore.info new file mode 100644 index 0000000000..b8e44bdfbe --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/rider.project.restore.info @@ -0,0 +1 @@ +17225689180408669 \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.dgspec.json b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.dgspec.json new file mode 100644 index 0000000000..0825170a7d --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.dgspec.json @@ -0,0 +1,68 @@ +{ + "format": 1, + "restore": { + "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj": {} + }, + "projects": { + "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj", + "projectName": "wssubscribe", + "projectPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/wssubscribe.csproj", + "packagesPath": "/root/.nuget/packages/", + "outputPath": "/mnt/e/github/TDengine/docs/examples/csharp/wssubscribe/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/root/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "dependencies": { + "TDengine.Connector": { + "target": "Package", + "version": "[3.1.*, )", + "generatePathProperty": true + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/root/.dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.props b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.props new file mode 100644 index 0000000000..939669445d --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.props @@ -0,0 +1,18 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /root/.nuget/packages/ + /root/.nuget/packages/ + PackageReference + 6.8.0 + + + + + + /root/.nuget/packages/tdengine.connector/3.1.3 + + \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.targets b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.targets new file mode 100644 index 0000000000..35a7576c5a --- /dev/null +++ b/docs/examples/csharp/wssubscribe/obj/wssubscribe.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/docs/examples/csharp/wssubscribe/wssubscribe.csproj b/docs/examples/csharp/wssubscribe/wssubscribe.csproj new file mode 100644 index 0000000000..3a2796a3af --- /dev/null +++ b/docs/examples/csharp/wssubscribe/wssubscribe.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0 + enable + enable + + + + + diff --git a/docs/examples/go/connect/afconn/main.go b/docs/examples/go/connect/afconn/main.go index bb2574a01b..3e4dff43ac 100644 --- a/docs/examples/go/connect/afconn/main.go +++ b/docs/examples/go/connect/afconn/main.go @@ -13,6 +13,6 @@ func main() { if err != nil { log.Fatalln("failed to connect, err:", err) } else { - fmt.Println("connected") + fmt.Println("Connected") } } diff --git a/docs/examples/go/connect/cgoexample/main.go b/docs/examples/go/connect/cgoexample/main.go index 881cf15ee3..9c9b414b47 100644 --- a/docs/examples/go/connect/cgoexample/main.go +++ b/docs/examples/go/connect/cgoexample/main.go @@ -9,6 +9,9 @@ import ( ) func main() { + // use + // var taosDSN = "root:taosdata@tcp(localhost:6030)/dbName" + // if you want to connect a specified database named "dbName". var taosDSN = "root:taosdata@tcp(localhost:6030)/" taos, err := sql.Open("taosSql", taosDSN) if err != nil { @@ -18,7 +21,3 @@ func main() { fmt.Println("Connected") defer taos.Close() } - -// use -// var taosDSN = "root:taosdata@tcp(localhost:6030)/dbName" -// if you want to connect a specified database named "dbName". diff --git a/docs/examples/go/connect/connpool/main.go b/docs/examples/go/connect/connpool/main.go new file mode 100644 index 0000000000..e3058fca3f --- /dev/null +++ b/docs/examples/go/connect/connpool/main.go @@ -0,0 +1,33 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + + _ "github.com/taosdata/driver-go/v3/taosSql" +) + +func main() { + // use + // var taosDSN = "root:taosdata@tcp(localhost:6030)/dbName" + // if you want to connect a specified database named "dbName". + var taosDSN = "root:taosdata@tcp(localhost:6030)/" + taos, err := sql.Open("taosSql", taosDSN) + if err != nil { + log.Fatalln("failed to connect TDengine, err:", err) + return + } + fmt.Println("Connected") + defer taos.Close() + // ANCHOR: pool + // SetMaxOpenConns sets the maximum number of open connections to the database. 0 means unlimited. + taos.SetMaxOpenConns(0) + // SetMaxIdleConns sets the maximum number of connections in the idle connection pool. + taos.SetMaxIdleConns(2) + // SetConnMaxLifetime sets the maximum amount of time a connection may be reused. + taos.SetConnMaxLifetime(0) + // SetConnMaxIdleTime sets the maximum amount of time a connection may be idle. + taos.SetConnMaxIdleTime(0) + // ANCHOR_END: pool +} diff --git a/docs/examples/go/connect/restexample/main.go b/docs/examples/go/connect/restexample/main.go index 67a129bf9c..ecc5110c60 100644 --- a/docs/examples/go/connect/restexample/main.go +++ b/docs/examples/go/connect/restexample/main.go @@ -9,6 +9,9 @@ import ( ) func main() { + // use + // var taosDSN = "root:taosdata@http(localhost:6041)/dbName" + // if you want to connect a specified database named "dbName". var taosDSN = "root:taosdata@http(localhost:6041)/" taos, err := sql.Open("taosRestful", taosDSN) if err != nil { @@ -18,7 +21,3 @@ func main() { fmt.Println("Connected") defer taos.Close() } - -// use -// var taosDSN = "root:taosdata@http(localhost:6041)/dbName" -// if you want to connect a specified database named "dbName". diff --git a/docs/examples/go/connect/wsexample/main.go b/docs/examples/go/connect/wsexample/main.go new file mode 100644 index 0000000000..c815f0aec5 --- /dev/null +++ b/docs/examples/go/connect/wsexample/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + + _ "github.com/taosdata/driver-go/v3/taosWS" +) + +func main() { + // use + // var taosDSN = "root:taosdata@ws(localhost:6041)/dbName" + // if you want to connect a specified database named "dbName". + var taosDSN = "root:taosdata@ws(localhost:6041)/" + taos, err := sql.Open("taosWS", taosDSN) + if err != nil { + log.Fatalln("failed to connect TDengine, err:", err) + return + } + fmt.Println("Connected") + defer taos.Close() +} diff --git a/docs/examples/go/go.mod b/docs/examples/go/go.mod index 716a0ef5dc..ed8fde2d9f 100644 --- a/docs/examples/go/go.mod +++ b/docs/examples/go/go.mod @@ -2,5 +2,12 @@ module goexample go 1.17 -require github.com/taosdata/driver-go/v3 v3.1.0 +require github.com/taosdata/driver-go/v3 v3.5.6 +require ( + github.com/google/uuid v1.3.0 // indirect + github.com/gorilla/websocket v1.5.0 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect +) diff --git a/docs/examples/go/go.sum b/docs/examples/go/go.sum index 13e13adaa1..61841429ee 100644 --- a/docs/examples/go/go.sum +++ b/docs/examples/go/go.sum @@ -1,15 +1,25 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/taosdata/driver-go/v3 v3.1.0/go.mod h1:H2vo/At+rOPY1aMzUV9P49SVX7NlXb3LAbKw+MCLrmU= +github.com/taosdata/driver-go/v3 v3.5.6 h1:LDVtMyT3B9p2VREsd5KKM91D4Y7P4kSdh2SQumXi8bk= +github.com/taosdata/driver-go/v3 v3.5.6/go.mod h1:H2vo/At+rOPY1aMzUV9P49SVX7NlXb3LAbKw+MCLrmU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/docs/examples/go/queryreqid/main.go b/docs/examples/go/queryreqid/main.go new file mode 100644 index 0000000000..c7dd3d9215 --- /dev/null +++ b/docs/examples/go/queryreqid/main.go @@ -0,0 +1,55 @@ +package main + +import ( + "context" + "database/sql" + "fmt" + "time" + + _ "github.com/taosdata/driver-go/v3/taosSql" +) + +func main() { + db, err := sql.Open("taosSql", "root:taosdata@tcp(localhost:6030)/") + if err != nil { + panic(err) + } + defer db.Close() + initEnv(db) + // ANCHOR: query_id + // use context to set request id + ctx := context.WithValue(context.Background(), "taos_req_id", int64(3)) + // execute query with context + rows, err := db.QueryContext(ctx, "SELECT ts, current, location FROM power.meters limit 1") + if err != nil { + panic(err) + } + for rows.Next() { + var ( + ts time.Time + current float32 + location string + ) + err = rows.Scan(&ts, ¤t, &location) + if err != nil { + panic(err) + } + fmt.Printf("ts: %s, current: %f, location: %s\n", ts, current, location) + } + // ANCHOR_END: query_id +} + +func initEnv(conn *sql.DB) { + _, err := conn.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = conn.Exec("CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + if err != nil { + panic(err) + } + _, err = conn.Exec("INSERT INTO power.d1001 USING power.meters TAGS (2, 'California.SanFrancisco') VALUES (NOW , 10.2, 219, 0.32)") + if err != nil { + panic(err) + } +} diff --git a/docs/examples/go/schemaless/native/main.go b/docs/examples/go/schemaless/native/main.go new file mode 100644 index 0000000000..b9cd70ef14 --- /dev/null +++ b/docs/examples/go/schemaless/native/main.go @@ -0,0 +1,41 @@ +package main + +import ( + "github.com/taosdata/driver-go/v3/af" +) + +func main() { + host := "127.0.0.1" + lineDemo := "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639" + telnetDemo := "metric_telnet 1707095283260 4 host=host0 interface=eth0" + jsonDemo := "{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}" + + conn, err := af.Open(host, "root", "taosdata", "", 0) + if err != nil { + panic(err) + } + defer conn.Close() + _, err = conn.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = conn.Exec("USE power") + if err != nil { + panic(err) + } + // insert influxdb line protocol + err = conn.InfluxDBInsertLines([]string{lineDemo}, "ms") + if err != nil { + panic(err) + } + // insert opentsdb telnet protocol + err = conn.OpenTSDBInsertTelnetLines([]string{telnetDemo}) + if err != nil { + panic(err) + } + // insert opentsdb json protocol + err = conn.OpenTSDBInsertJsonPayload(jsonDemo) + if err != nil { + panic(err) + } +} diff --git a/docs/examples/go/schemaless/ws/main.go b/docs/examples/go/schemaless/ws/main.go new file mode 100644 index 0000000000..c6807f213c --- /dev/null +++ b/docs/examples/go/schemaless/ws/main.go @@ -0,0 +1,57 @@ +package main + +import ( + "database/sql" + "fmt" + "log" + "time" + + "github.com/taosdata/driver-go/v3/common" + _ "github.com/taosdata/driver-go/v3/taosWS" + "github.com/taosdata/driver-go/v3/ws/schemaless" +) + +func main() { + host := "127.0.0.1" + lineDemo := "meters,groupid=2,location=California.SanFrancisco current=10.3000002f64,voltage=219i32,phase=0.31f64 1626006833639" + telnetDemo := "metric_telnet 1707095283260 4 host=host0 interface=eth0" + jsonDemo := "{\"metric\": \"metric_json\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}" + + db, err := sql.Open("taosWS", fmt.Sprintf("root:taosdata@ws(%s:6041)/", host)) + if err != nil { + log.Fatal(err) + } + defer db.Close() + _, err = db.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + log.Fatal(err) + } + s, err := schemaless.NewSchemaless(schemaless.NewConfig("ws://localhost:6041", 1, + schemaless.SetDb("power"), + schemaless.SetReadTimeout(10*time.Second), + schemaless.SetWriteTimeout(10*time.Second), + schemaless.SetUser("root"), + schemaless.SetPassword("taosdata"), + schemaless.SetErrorHandler(func(err error) { + log.Fatal(err) + }), + )) + if err != nil { + panic(err) + } + // insert influxdb line protocol + err = s.Insert(lineDemo, schemaless.InfluxDBLineProtocol, "ms", 0, common.GetReqID()) + if err != nil { + panic(err) + } + // insert opentsdb telnet line protocol + err = s.Insert(telnetDemo, schemaless.OpenTSDBTelnetLineProtocol, "ms", 0, common.GetReqID()) + if err != nil { + panic(err) + } + // insert opentsdb json format protocol + err = s.Insert(jsonDemo, schemaless.OpenTSDBJsonFormatProtocol, "s", 0, common.GetReqID()) + if err != nil { + panic(err) + } +} diff --git a/docs/examples/go/sqlquery/main.go b/docs/examples/go/sqlquery/main.go new file mode 100644 index 0000000000..12e1732b31 --- /dev/null +++ b/docs/examples/go/sqlquery/main.go @@ -0,0 +1,88 @@ +package main + +import ( + "database/sql" + "fmt" + "time" + + _ "github.com/taosdata/driver-go/v3/taosSql" +) + +func main() { + db, err := sql.Open("taosSql", "root:taosdata@tcp(localhost:6030)/") + if err != nil { + panic(err) + } + defer db.Close() + // ANCHOR: create_db_and_table + // create database + res, err := db.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + affected, err := res.RowsAffected() + if err != nil { + panic(err) + } + fmt.Println("create database affected:", affected) + // use database + res, err = db.Exec("USE power") + if err != nil { + panic(err) + } + affected, err = res.RowsAffected() + if err != nil { + panic(err) + } + fmt.Println("use database affected:", affected) + // create table + res, err = db.Exec("CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + affected, err = res.RowsAffected() + if err != nil { + panic(err) + } + fmt.Println("create table affected:", affected) + // ANCHOR_END: create_db_and_table + // ANCHOR: insert_data + // insert data, please make sure the database and table are created before + insertQuery := "INSERT INTO " + + "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 219, 0.31000) " + + "(NOW + 2a, 12.60000, 218, 0.33000) " + + "(NOW + 3a, 12.30000, 221, 0.31000) " + + "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + + "VALUES " + + "(NOW + 1a, 10.30000, 218, 0.25000) " + res, err = db.Exec(insertQuery) + if err != nil { + panic(err) + } + affected, err = res.RowsAffected() + if err != nil { + panic(err) + } + // you can check affectedRows here + fmt.Println("insert data affected:", affected) + // ANCHOR_END: insert_data + // ANCHOR: select_data + // query data, make sure the database and table are created before + rows, err := db.Query("SELECT ts, current, location FROM power.meters limit 100") + if err != nil { + panic(err) + } + for rows.Next() { + var ( + ts time.Time + current float32 + location string + ) + err = rows.Scan(&ts, ¤t, &location) + if err != nil { + panic(err) + } + // you can check data here + fmt.Printf("ts: %s, current: %f, location: %s\n", ts, current, location) + } + // ANCHOR_END: select_data +} diff --git a/docs/examples/go/stmt/native/main.go b/docs/examples/go/stmt/native/main.go new file mode 100644 index 0000000000..63986912da --- /dev/null +++ b/docs/examples/go/stmt/native/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "math/rand" + "time" + + "github.com/taosdata/driver-go/v3/af" + "github.com/taosdata/driver-go/v3/common" + "github.com/taosdata/driver-go/v3/common/param" +) + +func main() { + host := "127.0.0.1" + numOfSubTable := 10 + numOfRow := 10 + db, err := af.Open(host, "root", "taosdata", "", 0) + if err != nil { + panic(err) + } + defer db.Close() + // prepare database and table + _, err = db.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = db.Exec("USE power") + if err != nil { + panic(err) + } + _, err = db.Exec("CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + if err != nil { + panic(err) + } + // prepare statement + sql := "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)" + stmt := db.Stmt() + err = stmt.Prepare(sql) + if err != nil { + panic(err) + } + for i := 1; i <= numOfSubTable; i++ { + tableName := fmt.Sprintf("d_bind_%d", i) + tags := param.NewParam(2).AddInt(i).AddBinary([]byte(fmt.Sprintf("location_%d", i))) + // set tableName and tags + err = stmt.SetTableNameWithTags(tableName, tags) + if err != nil { + panic(err) + } + // bind column data + current := time.Now() + for j := 0; j < numOfRow; j++ { + row := param.NewParam(4). + AddTimestamp(current.Add(time.Millisecond*time.Duration(j)), common.PrecisionMilliSecond). + AddFloat(rand.Float32() * 30). + AddInt(rand.Intn(300)). + AddFloat(rand.Float32()) + err = stmt.BindRow(row) + if err != nil { + panic(err) + } + } + // add batch + err = stmt.AddBatch() + if err != nil { + panic(err) + } + // execute batch + err = stmt.Execute() + if err != nil { + panic(err) + } + // get affected rows + affected := stmt.GetAffectedRows() + // you can check exeResult here + fmt.Printf("table %s insert %d rows.\n", tableName, affected) + } + err = stmt.Close() + if err != nil { + panic(err) + } +} diff --git a/docs/examples/go/stmt/ws/main.go b/docs/examples/go/stmt/ws/main.go new file mode 100644 index 0000000000..ddb1d6e2a7 --- /dev/null +++ b/docs/examples/go/stmt/ws/main.go @@ -0,0 +1,102 @@ +package main + +import ( + "database/sql" + "fmt" + "math/rand" + "time" + + "github.com/taosdata/driver-go/v3/common" + "github.com/taosdata/driver-go/v3/common/param" + _ "github.com/taosdata/driver-go/v3/taosRestful" + "github.com/taosdata/driver-go/v3/ws/stmt" +) + +func main() { + host := "127.0.0.1" + numOfSubTable := 10 + numOfRow := 10 + db, err := sql.Open("taosRestful", fmt.Sprintf("root:taosdata@http(%s:6041)/", host)) + if err != nil { + panic(err) + } + defer db.Close() + // prepare database and table + _, err = db.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = db.Exec("CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + if err != nil { + panic(err) + } + + config := stmt.NewConfig(fmt.Sprintf("ws://%s:6041", host), 0) + config.SetConnectUser("root") + config.SetConnectPass("taosdata") + config.SetConnectDB("power") + config.SetMessageTimeout(common.DefaultMessageTimeout) + config.SetWriteWait(common.DefaultWriteWait) + + connector, err := stmt.NewConnector(config) + if err != nil { + panic(err) + } + // // prepare statement + sql := "INSERT INTO ? USING meters TAGS(?,?) VALUES (?,?,?,?)" + stmt, err := connector.Init() + if err != nil { + panic(err) + } + err = stmt.Prepare(sql) + if err != nil { + panic(err) + } + for i := 1; i <= numOfSubTable; i++ { + tableName := fmt.Sprintf("d_bind_%d", i) + tags := param.NewParam(2).AddInt(i).AddBinary([]byte(fmt.Sprintf("location_%d", i))) + tagsType := param.NewColumnType(2).AddInt().AddBinary(24) + columnType := param.NewColumnType(4).AddTimestamp().AddFloat().AddInt().AddFloat() + // set tableName + err = stmt.SetTableName(tableName) + if err != nil { + panic(err) + } + // set tags + err = stmt.SetTags(tags, tagsType) + if err != nil { + panic(err) + } + // bind column data + current := time.Now() + for j := 0; j < numOfRow; j++ { + columnData := make([]*param.Param, 4) + columnData[0] = param.NewParam(1).AddTimestamp(current.Add(time.Millisecond*time.Duration(j)), common.PrecisionMilliSecond) + columnData[1] = param.NewParam(1).AddFloat(rand.Float32() * 30) + columnData[2] = param.NewParam(1).AddInt(rand.Intn(300)) + columnData[3] = param.NewParam(1).AddFloat(rand.Float32()) + err = stmt.BindParam(columnData, columnType) + if err != nil { + panic(err) + } + } + // add batch + err = stmt.AddBatch() + if err != nil { + panic(err) + } + // execute batch + err = stmt.Exec() + if err != nil { + panic(err) + } + // get affected rows + affected := stmt.GetAffectedRows() + // you can check exeResult here + fmt.Printf("table %s insert %d rows.\n", tableName, affected) + } + err = stmt.Close() + if err != nil { + panic(err) + } +} diff --git a/docs/examples/go/tmq/native/main.go b/docs/examples/go/tmq/native/main.go new file mode 100644 index 0000000000..668898239e --- /dev/null +++ b/docs/examples/go/tmq/native/main.go @@ -0,0 +1,132 @@ +package main + +import ( + "database/sql" + "fmt" + "time" + + "github.com/taosdata/driver-go/v3/af/tmq" + tmqcommon "github.com/taosdata/driver-go/v3/common/tmq" + _ "github.com/taosdata/driver-go/v3/taosSql" +) + +var done = make(chan struct{}) + +func main() { + // init env + conn, err := sql.Open("taosSql", "root:taosdata@tcp(127.0.0.1:6030)/") + if err != nil { + panic(err) + } + defer func() { + conn.Close() + }() + initEnv(conn) + // ANCHOR: create_consumer + // create consumer + consumer, err := tmq.NewConsumer(&tmqcommon.ConfigMap{ + "td.connect.user": "root", + "td.connect.pass": "taosdata", + "auto.offset.reset": "latest", + "msg.with.table.name": "true", + "enable.auto.commit": "true", + "auto.commit.interval.ms": "1000", + "group.id": "group2", + "client.id": "1", + }) + if err != nil { + panic(err) + } + // ANCHOR_END: create_consumer + // ANCHOR: subscribe + err = consumer.Subscribe("topic_meters", nil) + if err != nil { + panic(err) + } + for i := 0; i < 50; i++ { + ev := consumer.Poll(100) + if ev != nil { + switch e := ev.(type) { + case *tmqcommon.DataMessage: + // process your data here + fmt.Printf("get message:%v\n", e) + // ANCHOR: commit_offset + // commit offset + topicPartition, err := consumer.CommitOffsets([]tmqcommon.TopicPartition{e.TopicPartition}) + if err != nil { + panic(err) + } + fmt.Println(topicPartition) + // ANCHOR_END: commit_offset + case tmqcommon.Error: + fmt.Printf("%% Error: %v: %v\n", e.Code(), e) + panic(e) + } + // commit all offsets + topicPartition, err := consumer.Commit() + if err != nil { + panic(err) + } + fmt.Println(topicPartition) + + } + } + // ANCHOR_END: subscribe + // ANCHOR: seek + // get assignment + partitions, err := consumer.Assignment() + if err != nil { + panic(err) + } + for i := 0; i < len(partitions); i++ { + fmt.Println(partitions[i]) + // seek to the beginning + err = consumer.Seek(tmqcommon.TopicPartition{ + Topic: partitions[i].Topic, + Partition: partitions[i].Partition, + Offset: 0, + }, 0) + if err != nil { + panic(err) + } + } + // ANCHOR_END: seek + // ANCHOR: close + // unsubscribe + err = consumer.Unsubscribe() + if err != nil { + panic(err) + } + // close consumer + err = consumer.Close() + if err != nil { + panic(err) + } + // ANCHOR_END: close + <-done +} + +func initEnv(conn *sql.DB) { + _, err := conn.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = conn.Exec("CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + if err != nil { + panic(err) + } + _, err = conn.Exec("CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM power.meters") + if err != nil { + panic(err) + } + go func() { + for i := 0; i < 10; i++ { + time.Sleep(time.Second) + _, err = conn.Exec("INSERT INTO power.d1001 USING power.meters TAGS (2, 'California.SanFrancisco') VALUES (NOW , 10.2, 219, 0.32)") + if err != nil { + panic(err) + } + } + done <- struct{}{} + }() +} diff --git a/docs/examples/go/tmq/ws/main.go b/docs/examples/go/tmq/ws/main.go new file mode 100644 index 0000000000..48e6714957 --- /dev/null +++ b/docs/examples/go/tmq/ws/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "database/sql" + "fmt" + "time" + + "github.com/taosdata/driver-go/v3/common" + tmqcommon "github.com/taosdata/driver-go/v3/common/tmq" + _ "github.com/taosdata/driver-go/v3/taosWS" + "github.com/taosdata/driver-go/v3/ws/tmq" +) + +var done = make(chan struct{}) + +func main() { + // init env + conn, err := sql.Open("taosWS", "root:taosdata@ws(127.0.0.1:6041)/") + if err != nil { + panic(err) + } + defer func() { + conn.Close() + }() + initEnv(conn) + // ANCHOR: create_consumer + // create consumer + consumer, err := tmq.NewConsumer(&tmqcommon.ConfigMap{ + "ws.url": "ws://127.0.0.1:6041", + "ws.message.channelLen": uint(0), + "ws.message.timeout": common.DefaultMessageTimeout, + "ws.message.writeWait": common.DefaultWriteWait, + "td.connect.user": "root", + "td.connect.pass": "taosdata", + "auto.offset.reset": "latest", + "msg.with.table.name": "true", + "enable.auto.commit": "true", + "auto.commit.interval.ms": "1000", + "group.id": "group2", + "client.id": "1", + }) + if err != nil { + panic(err) + } + // ANCHOR_END: create_consumer + // ANCHOR: subscribe + err = consumer.Subscribe("topic_meters", nil) + if err != nil { + panic(err) + } + for i := 0; i < 50; i++ { + ev := consumer.Poll(100) + if ev != nil { + switch e := ev.(type) { + case *tmqcommon.DataMessage: + // process your data here + fmt.Printf("get message:%v\n", e) + // ANCHOR: commit_offset + // commit offset + topicPartition, err := consumer.CommitOffsets([]tmqcommon.TopicPartition{e.TopicPartition}) + if err != nil { + panic(err) + } + fmt.Println(topicPartition) + // ANCHOR_END: commit_offset + case tmqcommon.Error: + fmt.Printf("%% Error: %v: %v\n", e.Code(), e) + panic(e) + } + // commit all offsets + topicPartition, err := consumer.Commit() + if err != nil { + panic(err) + } + fmt.Println(topicPartition) + + } + } + // ANCHOR_END: subscribe + // ANCHOR: seek + // get assignment + partitions, err := consumer.Assignment() + if err != nil { + panic(err) + } + for i := 0; i < len(partitions); i++ { + fmt.Println(partitions[i]) + // seek to the beginning + err = consumer.Seek(tmqcommon.TopicPartition{ + Topic: partitions[i].Topic, + Partition: partitions[i].Partition, + Offset: 0, + }, 0) + if err != nil { + panic(err) + } + } + // ANCHOR_END: seek + // ANCHOR: close + // unsubscribe + err = consumer.Unsubscribe() + if err != nil { + panic(err) + } + // close consumer + err = consumer.Close() + if err != nil { + panic(err) + } + // ANCHOR_END: close + <-done +} + +func initEnv(conn *sql.DB) { + _, err := conn.Exec("CREATE DATABASE IF NOT EXISTS power") + if err != nil { + panic(err) + } + _, err = conn.Exec("CREATE STABLE IF NOT EXISTS power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))") + if err != nil { + panic(err) + } + _, err = conn.Exec("CREATE TOPIC IF NOT EXISTS topic_meters AS SELECT ts, current, voltage, phase, groupid, location FROM power.meters") + if err != nil { + panic(err) + } + go func() { + for i := 0; i < 10; i++ { + time.Sleep(time.Second) + _, err = conn.Exec("INSERT INTO power.d1001 USING power.meters TAGS (2, 'California.SanFrancisco') VALUES (NOW , 10.2, 219, 0.32)") + if err != nil { + panic(err) + } + } + done <- struct{}{} + }() +} diff --git a/docs/zh/08-develop/01-connect/index.md b/docs/zh/08-develop/01-connect/index.md index 48af1f7a63..89c3dd7f69 100644 --- a/docs/zh/08-develop/01-connect/index.md +++ b/docs/zh/08-develop/01-connect/index.md @@ -220,7 +220,7 @@ taos = { version = "*", default-features = false, features = ["ws"] } 编辑项目配置文件中添加 [TDengine.Connector](https://www.nuget.org/packages/TDengine.Connector/) 的引用即可: -```xml title=csharp.csproj {12} +```xml title=csharp.csproj @@ -327,6 +327,40 @@ URL 和 Properties 的详细参数说明和如何使用详见 [url 规范](../.. + + 数据源名称具有通用格式,例如 [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php),但没有类型前缀(方括号表示可选): + + ``` text + [username[:password]@][protocol[(address)]]/[dbname][?param1=value1&...¶mN=valueN] + ``` + + 完整形式的 DSN: + + ```text + username:password@protocol(address)/dbname?param=value + ``` + + 支持的 DSN 参数如下 + + 原生连接: + + - `cfg` 指定 taos.cfg 目录 + - `cgoThread` 指定 cgo 同时执行的数量,默认为系统核数 + - `cgoAsyncHandlerPoolSize` 指定异步函数的 handle 大小,默认为 10000 + + REST 连接: + + - `disableCompression` 是否接受压缩数据,默认为 true 不接受压缩数据,如果传输数据使用 gzip 压缩设置为 false。 + - `readBufferSize` 读取数据的缓存区大小默认为 4K(4096),当查询结果数据量多时可以适当调大该值。 + - `token` 连接云服务时使用的 token。 + - `skipVerify` 是否跳过证书验证,默认为 false 不跳过证书验证,如果连接的是不安全的服务设置为 true。 + + WebSocket 连接: + + - `enableCompression` 是否发送压缩数据,默认为 false 不发送压缩数据,如果传输数据使用压缩设置为 true。 + - `readTimeout` 读取数据的超时时间,默认为 5m。 + - `writeTimeout` 写入数据的超时时间,默认为 10s。 + Rust 连接器使用 DSN 来创建连接, DSN 描述字符串基本结构如下: @@ -341,6 +375,34 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto + ConnectionStringBuilder 使用 key-value 对方式设置连接参数,key 为参数名,value 为参数值,不同参数之间使用分号 `;` 分割。 + + 例如: + + ```csharp + "protocol=WebSocket;host=127.0.0.1;port=6041;useSSL=false" + ``` + 支持的参数如下: + + - `host`:TDengine 运行实例的地址。 + - `port`:TDengine 运行实例的端口。 + - `username`:连接的用户名。 + - `password`:连接的密码。 + - `protocol`:连接的协议,可选值为 Native 或 WebSocket,默认为 Native。 + - `db`:连接的数据库。 + - `timezone`:时区,默认为本地时区。 + - `connTimeout`:连接超时时间,默认为 1 分钟。 + + WebSocket 连接额外支持以下参数: + + - `readTimeout`:读取超时时间,默认为 5 分钟。 + - `writeTimeout`:发送超时时间,默认为 10 秒。 + - `token`:连接 TDengine cloud 的 token。 + - `useSSL`:是否使用 SSL 连接,默认为 false。 + - `enableCompression`:是否启用 WebSocket 压缩,默认为 false。 + - `autoReconnect`:是否自动重连,默认为 false。 + - `reconnectRetryCount`:重连次数,默认为 3。 + - `reconnectIntervalMs`:重连间隔毫秒时间,默认为 2000。 @@ -383,7 +445,7 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto 下面是各语言连接器建立 Websocket 连接代码样例。演示了如何使用 Websocket 连接方式连接到 TDengine 数据库,并对连接设定一些参数。整个过程主要涉及到数据库连接的建立和异常处理。 - + ```java {{#include docs/examples/java/src/main/java/com/taos/example/WSConnectExample.java:main}} ``` @@ -394,7 +456,9 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto ``` - +```go +{{#include docs/examples/go/connect/wsexample/main.go}} +``` ```rust @@ -407,7 +471,9 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto ``` - +```csharp +{{#include docs/examples/csharp/wsConnect/Program.cs:main}} +``` @@ -428,36 +494,39 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto ```java {{#include docs/examples/java/src/main/java/com/taos/example/JNIConnectExample.java:main}} ``` - - - - - - - - + + + + + +```go +{{#include docs/examples/go/connect/cgoexample/main.go}} +``` + + ```rust {{#include docs/examples/rust/nativeexample/examples/connect.rs}} ``` - - - - - - - - - - - - - - + + +```csharp title="WebSocket 连接" +{{#include docs/examples/csharp/connect/Program.cs:main}} +``` + + + + + + + + + + ### REST 连接 -下面是各语言连接器建立 RESt 连接代码样例。演示了如何使用 REST 连接方式连接到 TDengine 数据库。整个过程主要涉及到数据库连接的建立和异常处理。 +下面是各语言连接器建立 REST 连接代码样例。演示了如何使用 REST 连接方式连接到 TDengine 数据库。整个过程主要涉及到数据库连接的建立和异常处理。 @@ -471,13 +540,15 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto ``` - + ```go + {{#include docs/examples/go/connect/restexample/main.go}} + ``` 不支持 - + C# 只支持 WebSocket 连接与原生连接 @@ -531,7 +602,13 @@ DSN 的详细说明和如何使用详见 [连接功能](../../reference/connecto - + +使用 `sql.Open` 创建出来的连接已经实现了连接池,可以通过 API 设置连接池参数,样例如下 + +```go +{{#include docs/examples/go/connect/connpool/main.go:pool}} +``` + @@ -563,7 +640,7 @@ let taos = pool.get()?; - + 不支持 diff --git a/docs/zh/08-develop/02-sql.md b/docs/zh/08-develop/02-sql.md index f24a35eb75..5476154158 100644 --- a/docs/zh/08-develop/02-sql.md +++ b/docs/zh/08-develop/02-sql.md @@ -11,6 +11,15 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL 下面介绍使用各语言连接器通过执行 SQL 完成建库、建表、写入数据和查询数据。 +:::note + +REST 连接:各编程语言的连接器封装使用 `HTTP` 请求的连接,支持数据写入和查询操作。 + +REST API:通过 `curl` 命令进行数据写入和查询操作。 + +::: + + ## 建库和表 下面以智能电表为例,展示使用各语言连接器如何执行 SQL 命令创建一个名为 `power` 的数据库,然后使用 `power` 数据库为默认数据库。 接着创建一个名为 `meters` 的超级表(STABLE),其表结构包含时间戳、电流、电压、相位等列,以及分组 ID 和位置作为标签。 @@ -28,6 +37,9 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL +```go +{{#include docs/examples/go/queryreqid/main.go:query_id}} +``` @@ -37,6 +49,9 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL +```csharp +{{#include docs/examples/csharp/wsInsert/Program.cs:create_db_and_table}} +``` @@ -47,6 +62,23 @@ TDengine 对 SQL 语言提供了全面的支持,允许用户以熟悉的 SQL > **注意**:如果不使用 `USE power` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 power.meters。 + + + +创建数据库 + +```bash +curl --location -uroot:taosdata 'http://127.0.0.1:6041/rest/sql' \ +--data 'CREATE DATABASE IF NOT EXISTS power' +``` + +创建表,在 url 中指定数据库为 `power` + +```bash +curl --location -uroot:taosdata 'http://127.0.0.1:6041/rest/sql/power' \ +--data 'CREATE STABLE IF NOT EXISTS meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))' +``` + > **注意**:如果不使用 `USE power` 指定数据库,则后续对表的操作都需要增加数据库名称作为前缀,如 `power.meters`。 @@ -68,6 +100,9 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```go +{{#include docs/examples/go/sqlquery/main.go:create_db_and_table}} +``` @@ -77,6 +112,9 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```csharp +{{#include docs/examples/csharp/wsInsert/Program.cs:insert_data}} +``` @@ -89,6 +127,16 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW + 1s 代表客户端当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒),s(秒),m(分),h(小时),d(天),w(周),n(月),y(年)。 + + + +写入数据 + +```bash +curl --location -uroot:taosdata 'http://127.0.0.1:6041/rest/sql' \ +--data 'INSERT INTO power.d1001 USING power.meters TAGS(2,'\''California.SanFrancisco'\'') VALUES (NOW + 1a, 10.30000, 219, 0.31000) (NOW + 2a, 12.60000, 218, 0.33000) (NOW + 3a, 12.30000, 221, 0.31000) power.d1002 USING power.meters TAGS(3, '\''California.SanFrancisco'\'') VALUES (NOW + 1a, 10.30000, 218, 0.25000)' +``` + @@ -108,6 +156,9 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```go +{{#include docs/examples/go/sqlquery/main.go:insert_data}} +``` @@ -117,6 +168,9 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW +```csharp +{{#include docs/examples/csharp/wsInsert/Program.cs:select_data}} +``` @@ -126,6 +180,16 @@ NOW 为系统内部函数,默认为客户端所在计算机当前时间。 NOW ``` + + + +查询数据 + +```bash +curl --location -uroot:taosdata 'http://127.0.0.1:6041/rest/sql' \ +--data 'SELECT ts, current, location FROM power.meters limit 100' +``` + @@ -153,6 +217,9 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId +```go +{{#include docs/examples/go/sqlquery/main.go:select_data}} +``` @@ -162,6 +229,9 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId +```csharp +{{#include docs/examples/csharp/wsInsert/Program.cs:query_id}} +``` @@ -171,5 +241,15 @@ reqId 可用于请求链路追踪,reqId 就像分布式系统中的 traceId ``` + + + +查询数据,指定 reqId 为 3 + +```bash +curl --location -uroot:taosdata 'http://127.0.0.1:6041/rest/sql?req_id=3' \ +--data 'SELECT ts, current, location FROM power.meters limit 1' +``` + diff --git a/docs/zh/08-develop/04-schemaless.md b/docs/zh/08-develop/04-schemaless.md index 9c136cb109..71c9a5e1bd 100644 --- a/docs/zh/08-develop/04-schemaless.md +++ b/docs/zh/08-develop/04-schemaless.md @@ -179,6 +179,9 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO +```go +{{#include docs/examples/go/schemaless/ws/main.go}} +``` @@ -188,6 +191,9 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO +```csharp +{{#include docs/examples/csharp/wssml/Program.cs:main}} +``` @@ -210,22 +216,25 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO_SECONDS, 1L); ``` - - - - - - + + + + + + 除 DSN 不同,其余同 Websocket 代码示例。 - - - - - - - - - + + +```csharp +{{#include docs/examples/csharp/nativesml/Program.cs:main}} +``` + + + + + + + @@ -238,11 +247,15 @@ writer.write(lineDemo, SchemalessProtocolType.LINE, SchemalessTimestampType.NANO + ```go + {{#include docs/examples/go/schemaless/native/main.go}} + ``` 不支持 + 不支持 diff --git a/docs/zh/08-develop/05-stmt.md b/docs/zh/08-develop/05-stmt.md index 5dd9daaed5..b8c3c60d47 100644 --- a/docs/zh/08-develop/05-stmt.md +++ b/docs/zh/08-develop/05-stmt.md @@ -39,7 +39,9 @@ import TabItem from "@theme/TabItem"; ``` - +```go +{{#include docs/examples/go/stmt/ws/main.go}} +``` @@ -55,7 +57,9 @@ import TabItem from "@theme/TabItem"; ``` - +```csharp +{{#include docs/examples/csharp/wsStmt/Program.cs:main}} +``` @@ -83,13 +87,17 @@ import TabItem from "@theme/TabItem"; - +```go +{{#include docs/examples/go/stmt/native/main.go}} +``` 除 DSN 不同,其余同 Websocket 代码示例。 - +```csharp +{{#include docs/examples/csharp/stmtInsert/Program.cs:main}} +``` diff --git a/docs/zh/08-develop/07-tmq.md b/docs/zh/08-develop/07-tmq.md index 405d227e8e..cce21522cf 100644 --- a/docs/zh/08-develop/07-tmq.md +++ b/docs/zh/08-develop/07-tmq.md @@ -56,6 +56,19 @@ Java 连接器创建消费者的参数为 Properties, 可以设置的参数列 +创建消费者支持属性列表: + +- `ws.url`:WebSocket 连接地址。 +- `ws.message.channelLen`:WebSocket 消息通道缓存长度,默认 0。 +- `ws.message.timeout`:WebSocket 消息超时时间,默认 5m。 +- `ws.message.writeWait`:WebSocket 写入消息超时时间,默认 10s。 +- `ws.message.enableCompression`:WebSocket 是否启用压缩,默认 false。 +- `ws.autoReconnect`:WebSocket 是否自动重连,默认 false。 +- `ws.reconnectIntervalMs`:WebSocket 重连间隔时间毫秒,默认 2000。 +- `ws.reconnectRetryCount`:WebSocket 重连重试次数,默认 3。 + +其他参数见上表。 + Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请参考 [DSN](../../reference/connector/rust/#dsn) @@ -66,6 +79,16 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 +创建消费者支持属性列表: + +- `useSSL`:是否使用 SSL 连接,默认为 false。 +- `token`:连接 TDengine cloud 的 token。 +- `ws.message.enableCompression`:是否启用 WebSocket 压缩,默认为 false。 +- `ws.autoReconnect`:是否自动重连,默认为 false。 +- `ws.reconnect.retry.count`:重连次数,默认为 3。 +- `ws.reconnect.interval.ms`:重连间隔毫秒时间,默认为 2000。 + +其他参数见上表。 @@ -99,7 +122,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go:create_consumer}} +``` @@ -116,7 +141,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs:create_consumer}} +``` @@ -156,7 +183,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go:create_consumer}} +``` @@ -164,7 +193,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs:create_consumer}} +``` @@ -204,7 +235,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go:subscribe}} +``` @@ -216,7 +249,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs:subscribe}} +``` @@ -248,7 +283,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go:subscribe}} +``` @@ -256,7 +293,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs:subscribe}} +``` @@ -293,7 +332,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go:seek}} +``` @@ -305,7 +346,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs:seek}} +``` @@ -337,7 +380,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go:seek}} +``` @@ -345,7 +390,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs:seek}} +``` @@ -384,7 +431,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go:commit_offset}} +``` @@ -396,7 +445,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs:commit_offset}} +``` @@ -430,7 +481,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go:commit_offset}} +``` @@ -442,7 +495,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs:commit_offset}} +``` @@ -481,7 +536,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go:close}} +``` @@ -493,7 +550,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs:close}} +``` @@ -511,7 +570,7 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 ### 原生连接 - + 同 Websocket 代码样例。 @@ -526,7 +585,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go:close}} +``` @@ -538,7 +599,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs:close}} +``` @@ -578,7 +641,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/ws/main.go}} +``` @@ -590,7 +655,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/wssubscribe/Program.cs}} +``` @@ -631,7 +698,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```go +{{#include docs/examples/go/tmq/native/main.go}} +``` @@ -643,7 +712,9 @@ Rust 连接器创建消费者的参数为 DSN, 可以设置的参数列表请 - +```csharp +{{#include docs/examples/csharp/subscribe/Program.cs}} +``` diff --git a/docs/zh/14-reference/05-connector/20-go.mdx b/docs/zh/14-reference/05-connector/20-go.mdx index c53f681f06..ff10a31124 100644 --- a/docs/zh/14-reference/05-connector/20-go.mdx +++ b/docs/zh/14-reference/05-connector/20-go.mdx @@ -12,16 +12,6 @@ import RequestId from "./_request_id.mdx"; `driver-go` 是 TDengine 的官方 Go 语言连接器,实现了 Go 语言 [database/sql](https://golang.org/pkg/database/sql/) 包的接口。Go 开发人员可以通过它开发存取 TDengine 集群数据的应用软件。 -## 连接方式 - -`driver-go` 提供三种建立连接的方式。 - -* **原生连接**,通过 TDengine 客户端驱动程序(taosc)原生连接 TDengine 实例,支持数据写入、查询、数据订阅、schemaless 接口和参数绑定接口等功能。 -* **REST 连接**,通过 taosAdapter 提供的 HTTP 接口连接 TDengine 实例,不支持 schemaless 和数据订阅等特性。 -* **Websocket 连接**,通过 taosAdapter 提供的 Websocket 接口连接 TDengine 实例,WebSocket 连接实现的功能集合和原生连接有少量不同。 - -连接方式的详细介绍请参考:[连接器建立连接的方式](../../develop/connect/#连接器建立连接的方式) - ## 兼容性 支持最低 Go 版本 1.14,建议使用最新 Go 版本 @@ -74,300 +64,6 @@ REST 连接支持所有能运行 Go 的平台。 **注意**:JSON 类型仅在 tag 中支持。 -## 安装步骤 - -### 安装前准备 - -* 安装 Go 开发环境(Go 1.14 及以上,GCC 4.8.5 及以上) -* 如果使用原生连接器,请安装 TDengine 客户端驱动,具体步骤请参考[安装客户端驱动](../#安装客户端驱动) - -配置好环境变量,检查命令: - -* ```go env``` -* ```gcc -v``` - -### 安装连接器 - -1. 使用 `go mod` 命令初始化项目: - - ```text - go mod init taos-demo - ``` - -2. 引入 taosSql : - - ```go - import ( - "database/sql" - _ "github.com/taosdata/driver-go/v3/taosSql" - ) - ``` - -3. 使用 `go mod tidy` 更新依赖包: - - ```text - go mod tidy - ``` - -4. 使用 `go run taos-demo` 运行程序或使用 `go build` 命令编译出二进制文件。 - - ```text - go run taos-demo - go build - ``` - -## 建立连接 - -数据源名称具有通用格式,例如 [PEAR DB](http://pear.php.net/manual/en/package.database.db.intro-dsn.php),但没有类型前缀(方括号表示可选): - -``` text -[username[:password]@][protocol[(address)]]/[dbname][?param1=value1&...¶mN=valueN] -``` - -完整形式的 DSN: - -```text -username:password@protocol(address)/dbname?param=value -``` - - - - -_taosSql_ 通过 cgo 实现了 Go 的 `database/sql/driver` 接口。只需要引入驱动就可以使用 [`database/sql`](https://golang.org/pkg/database/sql/) 的接口。 - -使用 `taosSql` 作为 `driverName` 并且使用一个正确的 [DSN](#DSN) 作为 `dataSourceName`,DSN 支持的参数: - -* cfg 指定 taos.cfg 目录 - -示例: - -```go -package main - -import ( - "database/sql" - "fmt" - - _ "github.com/taosdata/driver-go/v3/taosSql" -) - -func main() { - var taosUri = "root:taosdata@tcp(localhost:6030)/" - taos, err := sql.Open("taosSql", taosUri) - if err != nil { - fmt.Println("failed to connect TDengine, err:", err) - return - } -} -``` - - - - -_taosRestful_ 通过 `http client` 实现了 Go 的 `database/sql/driver` 接口。只需要引入驱动就可以使用[`database/sql`](https://golang.org/pkg/database/sql/)的接口。 - -使用 `taosRestful` 作为 `driverName` 并且使用一个正确的 [DSN](#DSN) 作为 `dataSourceName`,DSN 支持的参数: - -* `disableCompression` 是否接受压缩数据,默认为 true 不接受压缩数据,如果传输数据使用 gzip 压缩设置为 false。 -* `readBufferSize` 读取数据的缓存区大小默认为 4K(4096),当查询结果数据量多时可以适当调大该值。 - -示例: - -```go -package main - -import ( - "database/sql" - "fmt" - - _ "github.com/taosdata/driver-go/v3/taosRestful" -) - -func main() { - var taosUri = "root:taosdata@http(localhost:6041)/" - taos, err := sql.Open("taosRestful", taosUri) - if err != nil { - fmt.Println("failed to connect TDengine, err:", err) - return - } -} -``` - - - - -_taosWS_ 通过 `WebSocket` 实现了 Go 的 `database/sql/driver` 接口。只需要引入驱动(driver-go 最低版本 3.0.2)就可以使用[`database/sql`](https://golang.org/pkg/database/sql/)的接口。 - -使用 `taosWS` 作为 `driverName` 并且使用一个正确的 [DSN](#DSN) 作为 `dataSourceName`,DSN 支持的参数: - -* `writeTimeout` 通过 WebSocket 发送数据的超时时间。 -* `readTimeout` 通过 WebSocket 接收响应数据的超时时间。 - -示例: - -```go -package main - -import ( - "database/sql" - "fmt" - - _ "github.com/taosdata/driver-go/v3/taosWS" -) - -func main() { - var taosUri = "root:taosdata@ws(localhost:6041)/" - taos, err := sql.Open("taosWS", taosUri) - if err != nil { - fmt.Println("failed to connect TDengine, err:", err) - return - } -} -``` - - - - -### 指定 URL 和 Properties 获取连接 - -Go 连接器不支持此功能 - -### 配置参数的优先级 - -Go 连接器不支持此功能 - -## 使用示例 - -### 创建数据库和表 - -```go -{{#include docs/examples/go/demo/query/main.go:create_db_and_table}} -``` - -### 插入数据 - -```go -{{#include docs/examples/go/demo/query/main.go:insert_data}} -``` - -### 查询数据 - -```go -{{#include docs/examples/go/demo/query/main.go:query_data}} -``` - -### 执行带有 reqId 的 SQL - - - -```go -{{#include docs/examples/go/demo/query/main.go:with_reqid}} -``` - -### 通过参数绑定写入数据 - - - - -```go -{{#include docs/examples/go/demo/stmt/main.go}} -``` - - - - -```go -{{#include docs/examples/go/demo/stmtws/main.go}} -``` - - - - -### 无模式写入 - - - - -```go -{{#include docs/examples/go/demo/sml/main.go}} -``` - - - - -```go -{{#include docs/examples/go/demo/smlws/main.go}} -``` - - - - -### 执行带有 reqId 的无模式写入 - -```go -func (s *Schemaless) Insert(lines string, protocol int, precision string, ttl int, reqID int64) error -``` - -可以通过 `common.GetReqID()` 获取唯一 id。 - -### 数据订阅 - -TDengine Go 连接器支持订阅功能,应用 API 如下: - -#### 创建 Topic - -```go -{{#include docs/examples/go/demo/consumer/main.go:create_topic}} -``` - -#### 创建 Consumer - -```go -{{#include docs/examples/go/demo/consumer/main.go:create_consumer}} -``` - -#### 订阅消费数据 - -```go -{{#include docs/examples/go/demo/consumer/main.go:poll_data}} -``` - -#### 指定订阅 Offset - -```go -{{#include docs/examples/go/demo/consumer/main.go:consumer_seek}} -``` - -#### 关闭订阅 - -```go -{{#include docs/examples/go/demo/consumer/main.go:consumer_close}} -``` - -#### 完整示例 - - - - -```go -{{#include docs/examples/go/demo/consumer/main.go}} -``` - - - - -```go -{{#include docs/examples/go/demo/consumerws/main.go}} -``` - - - - -### 更多示例程序 - -* [示例程序](https://github.com/taosdata/driver-go/tree/3.0/examples) -* [视频教程](https://www.taosdata.com/blog/2020/11/11/1951.html)。 - ## 常见问题 1. database/sql 中 stmt(参数绑定)相关接口崩溃 @@ -1065,7 +761,7 @@ type ConfigMap map[string]ConfigValue - `ws.reconnectIntervalMs`:WebSocket 重连间隔时间毫秒,默认 2000。 - `ws.reconnectRetryCount`:WebSocket 重连重试次数,默认 3。 -其他参数请参考:[Consumer 参数列表](../../../develop/tmq/#数据订阅相关参数), 注意TDengine服务端自 3.2.0.0 版本开始消息订阅中的 auto.offset.reset 默认值发生变化。 +其他参数请参考:[Consumer 参数列表](../../../develop/tmq/#创建参数), 注意TDengine服务端自 3.2.0.0 版本开始消息订阅中的 auto.offset.reset 默认值发生变化。 - `func (c *Consumer) Subscribe(topic string, rebalanceCb RebalanceCb) error` - **接口说明**:订阅主题。 @@ -1195,4 +891,6 @@ type TopicPartition struct { ## 附录 -[driver-go 文档](https://pkg.go.dev/github.com/taosdata/driver-go/v3) +* [driver-go 文档](https://pkg.go.dev/github.com/taosdata/driver-go/v3)。 +* [示例程序](https://github.com/taosdata/driver-go/tree/3.0/examples)。 +* [视频教程](https://www.taosdata.com/blog/2020/11/11/1951.html)。 diff --git a/docs/zh/14-reference/05-connector/40-csharp.mdx b/docs/zh/14-reference/05-connector/40-csharp.mdx index ad316d581c..9ac4369c57 100644 --- a/docs/zh/14-reference/05-connector/40-csharp.mdx +++ b/docs/zh/14-reference/05-connector/40-csharp.mdx @@ -70,1144 +70,6 @@ TDengine 不再支持 32 位 Windows 平台。 JSON 类型仅在 tag 中支持。 ::: -## 安装步骤 - -### 安装前准备 - -* 安装 [.NET SDK](https://dotnet.microsoft.com/download) -* [Nuget 客户端](https://docs.microsoft.com/en-us/nuget/install-nuget-client-tools) (可选安装) -* 对于 Native 连接方式,需要安装 TDengine 客户端驱动,具体步骤请参考[安装客户端驱动](../#安装客户端驱动),WebSocket 连接方式无需安装。 - -### 安装连接器 - -可以在当前 .NET 项目的路径下,通过 dotnet CLI 添加 Nuget package `TDengine.Connector` 到当前项目。 - -``` bash -dotnet add package TDengine.Connector -``` - -也可以修改当前项目的 `.csproj` 文件,添加如下 ItemGroup。 - -``` XML - - - -``` - -## 建立连接 - - - - -``` csharp -var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - - - - -```csharp -var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); -using (var client = DbDriver.Open(builder)) -{ - Console.WriteLine("connected"); -} -``` - - - -ConnectionStringBuilder 支持的参数如下: -* protocol: 连接协议,可选值为 Native 或 WebSocket,默认为 Native -* host: TDengine 或 taosadapter 运行实例的地址 -* port: TDengine 或 taosadapter 运行实例的端口 - * 当 protocol 为 WebSocket 时 useSSL 为 false 时,port 默认为 6041 - * 当 protocol 为 WebSocket 时 useSSL 为 true 时,port 默认为 443 -* useSSL: 是否使用 SSL 连接,仅当 protocol 为 WebSocket 时有效,默认为 false -* token: 连接 TDengine cloud 的 token,仅当 protocol 为 WebSocket 时有效 -* username: 连接 TDengine 的用户名 -* password: 连接 TDengine 的密码 -* db: 连接 TDengine 的数据库 -* timezone: 解析时间结果的时区,默认为 `TimeZoneInfo.Local`,使用 `TimeZoneInfo.FindSystemTimeZoneById` 方法解析字符串为 `TimeZoneInfo` 对象。 -* connTimeout: WebSocket 连接超时时间,仅当 protocol 为 WebSocket 时有效,默认为 1 分钟,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* readTimeout: WebSocket 读超时时间,仅当 protocol 为 WebSocket 时有效,默认为 5 分钟,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* writeTimeout: WebSocket 写超时时间,仅当 protocol 为 WebSocket 时有效,默认为 10 秒,使用 `TimeSpan.Parse` 方法解析字符串为 `TimeSpan` 对象。 -* autoReconnect: 是否自动重连(连接器版本 3.1.3 及以上生效),默认为 false -> **注意**:启用自动重连仅对简单执行 SQL 语句以及 无模式写入、数据订阅有效。对于参数绑定无效。自动重连仅对连接建立时通过参数指定数据库有效,对后面的 `use db` 语句切换数据库无效。 - -* reconnectRetryCount: 重连次数(连接器版本 3.1.3 及以上生效),默认为 3 -* reconnectIntervalMs: 重连间隔时间(连接器版本 3.1.3 及以上生效),默认为 2000 - -### 指定 URL 和 Properties 获取连接 - -C# 连接器不支持此功能 - -### 配置参数的优先级 - -C# 连接器不支持此功能 - -## 使用示例 - -### 创建数据库和表 - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -### 插入数据 - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - string insertQuery = - "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.30000, 219, 0.31000) " + - "('2023-10-03 14:38:15.000', 12.60000, 218, 0.33000) " + - "('2023-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + - "power.d1002 USING power.meters TAGS(3, 'California.SanFrancisco') " + - "VALUES " + - "('2023-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + - "power.d1003 USING power.meters TAGS(2,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.500', 11.80000, 221, 0.28000) " + - "('2023-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + - "power.d1004 USING power.meters TAGS(3,'California.LosAngeles') " + - "VALUES " + - "('2023-10-03 14:38:05.000', 10.80000, 223, 0.29000) " + - "('2023-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; - client.Exec(insertQuery); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -### 查询数据 - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQuery -{ - internal class Query - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("use power"); - string query = "SELECT * FROM meters"; - using (var rows = client.Query(query)) - { - while (rows.Read()) - { - Console.WriteLine($"{((DateTime)rows.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {rows.GetValue(1)}, {rows.GetValue(2)}, {rows.GetValue(3)}, {rows.GetValue(4)}, {Encoding.UTF8.GetString((byte[])rows.GetValue(5))}"); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -### 执行带有 reqId 的 SQL - - - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSQueryWithReqID -{ - internal abstract class QueryWithReqID - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec($"create database if not exists test_db",ReqId.GetReqId()); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -### 通过参数绑定写入数据 - - - - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeStmt -{ - internal abstract class NativeStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSStmt -{ - internal abstract class WSStmt - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - using (var stmt = client.StmtInit()) - { - stmt.Prepare( - "Insert into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(?,?,?,?)"); - var ts = new DateTime(2023, 10, 03, 14, 38, 05, 000); - stmt.BindRow(new object[] { ts, (float)10.30000, (int)219, (float)0.31000 }); - stmt.AddBatch(); - stmt.Exec(); - var affected = stmt.Affected(); - Console.WriteLine($"affected rows: {affected}"); - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - - - - -注意:使用 BindRow 需要注意原始 C# 列类型与 TDengine 列类型的需要一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 - -### 无模式写入 - - - - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - - - - -```csharp -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSchemaless -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = - new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - client.Exec("create database sml"); - client.Exec("use sml"); - var influxDBData = - "st,t1=3i64,t2=4f64,t3=\"t3\" c1=3i64,c3=L\"passit\",c2=false,c4=4f64 1626006833639000000"; - client.SchemalessInsert(new string[] { influxDBData }, - TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NANO_SECONDS, 0, ReqId.GetReqId()); - var telnetData = "stb0_0 1626006833 4 host=host0 interface=eth0"; - client.SchemalessInsert(new string[] { telnetData }, - TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - var jsonData = - "{\"metric\": \"meter_current\",\"timestamp\": 1626846400,\"value\": 10.3, \"tags\": {\"groupid\": 2, \"location\": \"California.SanFrancisco\", \"id\": \"d1001\"}}"; - client.SchemalessInsert(new string[] { jsonData }, TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, - TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS, 0, ReqId.GetReqId()); - } - } - } -} -``` - - - - -### 执行带有 reqId 的无模式写入 - -```csharp -public void SchemalessInsert(string[] lines, TDengineSchemalessProtocol protocol, - TDengineSchemalessPrecision precision, - int ttl, long reqId) -``` - -### 数据订阅 - -#### 创建 Topic - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Text; -using TDengine.Driver; -using TDengine.Driver.Client; - -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("create database power"); - client.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - } -} -``` - - - - -#### 创建 Consumer - - - - -```csharp -var cfg = new Dictionary() -{ - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - - - - -```csharp -var cfg = new Dictionary() -{ - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port", "6041" }, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, -}; -var consumer = new ConsumerBuilder>(cfg).Build(); -``` - - - - -consumer 支持的配置参数如下: -* td.connect.type: 连接类型,可选值为 Native 或 WebSocket,默认为 Native -* td.connect.ip: TDengine 或 taosadapter 运行实例的地址 -* td.connect.port: TDengine 或 taosadapter 运行实例的端口 - * 当 td.connect.type 为 WebSocket 且 useSSL 为 false 时,td.connect.port 默认为 6041 - * 当 td.connect.type 为 WebSocket 且 useSSL 为 true 时,td.connect.port 默认为 443 -* useSSL: 是否使用 SSL 连接,仅当 td.connect.type 为 WebSocket 时有效,默认为 false -* token: 连接 TDengine cloud 的 token,仅当 td.connect.type 为 WebSocket 时有效 - -* td.connect.user: 连接 TDengine 的用户名 -* td.connect.pass: 连接 TDengine 的密码 -* group.id: 消费者组 ID -* client.id: 消费者 ID -* enable.auto.commit: 是否自动提交 offset,默认为 true -* auto.commit.interval.ms: 自动提交 offset 的间隔时间,默认为 5000 毫秒 -* auto.offset.reset: 当 offset 不存在时,从哪里开始消费,可选值为 earliest 或 latest,默认为 latest -* msg.with.table.name: 消息是否包含表名 -* ws.message.enableCompression: 是否启用 WebSocket 压缩(dotnet 版本 6 及以上,连接器版本 3.1.1 及以上生效),默认为 false -* ws.autoReconnect: 是否自动重连(连接器版本 3.1.3 及以上生效),默认为 false -* ws.reconnect.retry.count: 重连次数(连接器版本 3.1.3 及以上生效),默认为 3 -* ws.reconnect.interval.ms: 重连间隔时间(连接器版本 3.1.3 及以上生效),默认为 2000 - - -支持订阅结果集 `Dictionary` key 为列名,value 为列值。 - -如果使用 object 接收列值,需要注意: -* 原始 C# 列类型与 TDengine 列类型的需要一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 -* 列名与 class 属性名一致,并可读写。 -* 明确设置 value 解析器`ConsumerBuilder.SetValueDeserializer(new ReferenceDeserializer());` - -样例如下 - -结果 class - -```csharp - class Result - { - public DateTime ts { get; set; } - public float current { get; set; } - public int voltage { get; set; } - public float phase { get; set; } - } -``` - -设置解析器 - -```csharp -var tmqBuilder = new ConsumerBuilder(cfg); -tmqBuilder.SetValueDeserializer(new ReferenceDeserializer()); -var consumer = tmqBuilder.Build(); -``` - -也可实现自定义解析器,实现 `IDeserializer` 接口并通过`ConsumerBuilder.SetValueDeserializer`方法传入。 - -```csharp - public interface IDeserializer - { - T Deserialize(ITMQRows data, bool isNull, SerializationContext context); - } -``` - -#### 订阅消费数据 - -```csharp -consumer.Subscribe(new List() { "topic_meters" }); -while (true) -{ - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - } -} -``` - -#### 指定订阅 Offset - -```csharp -consumer.Assignment.ForEach(a => -{ - Console.WriteLine($"{a}, seek to 0"); - consumer.Seek(new TopicPartitionOffset(a.Topic, a.Partition, 0)); - Thread.Sleep(TimeSpan.FromSeconds(1)); -}); -``` - -#### 提交 Offset - -```csharp -public void Commit(ConsumeResult consumerResult) -public List Commit() -public void Commit(IEnumerable offsets) -``` - -#### 关闭订阅 - -```csharp -consumer.Unsubscribe(); -consumer.Close(); -``` - -#### 完整示例 - - - - -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; - -namespace NativeSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "127.0.0.1" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "td.connect.port", "6030" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - consumer.Commit(); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("host=localhost;port=6030;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` - - - - -```csharp -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using TDengine.Driver; -using TDengine.Driver.Client; -using TDengine.TMQ; - -namespace WSSubscription -{ - internal class Program - { - public static void Main(string[] args) - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - try - { - client.Exec("CREATE DATABASE power"); - client.Exec("USE power"); - client.Exec( - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"); - client.Exec("CREATE TOPIC topic_meters as SELECT * from power.meters"); - var cfg = new Dictionary() - { - { "td.connect.type", "WebSocket" }, - { "group.id", "group1" }, - { "auto.offset.reset", "latest" }, - { "td.connect.ip", "localhost" }, - { "td.connect.port", "6041" }, - { "useSSL", "false" }, - { "td.connect.user", "root" }, - { "td.connect.pass", "taosdata" }, - { "client.id", "tmq_example" }, - { "enable.auto.commit", "true" }, - { "msg.with.table.name", "false" }, - }; - var consumer = new ConsumerBuilder>(cfg).Build(); - consumer.Subscribe(new List() { "topic_meters" }); - Task.Run(InsertData); - while (true) - { - using (var cr = consumer.Consume(500)) - { - if (cr == null) continue; - foreach (var message in cr.Message) - { - Console.WriteLine( - $"message {{{((DateTime)message.Value["ts"]).ToString("yyyy-MM-dd HH:mm:ss.fff")}, " + - $"{message.Value["current"]}, {message.Value["voltage"]}, {message.Value["phase"]}}}"); - } - consumer.Commit(); - } - } - } - catch (Exception e) - { - Console.WriteLine(e.ToString()); - throw; - } - } - } - - static void InsertData() - { - var builder = new ConnectionStringBuilder("protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"); - using (var client = DbDriver.Open(builder)) - { - while (true) - { - client.Exec("INSERT into power.d1001 using power.meters tags(2,'California.SanFrancisco') values(now,11.5,219,0.30)"); - Task.Delay(1000).Wait(); - } - } - } - } -} -``` - - - - -### ADO.NET - -C# 连接器支持 ADO.NET 接口,可以通过 ADO.NET 接口连接 TDengine 运行实例,进行数据写入、查询等操作。 - - - - -```csharp -using System; -using TDengine.Data.Client; - -namespace NativeADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "host=localhost;port=6030;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - - - - -```csharp -using System; -using TDengine.Data.Client; - -namespace WSADO -{ - internal class Program - { - public static void Main(string[] args) - { - const string connectionString = "protocol=WebSocket;host=localhost;port=6041;useSSL=false;username=root;password=taosdata"; - using (var connection = new TDengineConnection(connectionString)) - { - try - { - connection.Open(); - using (var command = new TDengineCommand(connection)) - { - command.CommandText = "create database power"; - command.ExecuteNonQuery(); - connection.ChangeDatabase("power"); - command.CommandText = - "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (groupId INT, location BINARY(24))"; - command.ExecuteNonQuery(); - command.CommandText = "INSERT INTO " + - "power.d1001 USING power.meters TAGS(2,'California.SanFrancisco') " + - "VALUES " + - "(?,?,?,?)"; - var parameters = command.Parameters; - parameters.Add(new TDengineParameter("@0", new DateTime(2023,10,03,14,38,05,000))); - parameters.Add(new TDengineParameter("@1", (float)10.30000)); - parameters.Add(new TDengineParameter("@2", (int)219)); - parameters.Add(new TDengineParameter("@3", (float)0.31000)); - command.ExecuteNonQuery(); - command.Parameters.Clear(); - command.CommandText = "SELECT * FROM meters"; - using (var reader = command.ExecuteReader()) - { - while (reader.Read()) - { - Console.WriteLine( - $"{((DateTime) reader.GetValue(0)):yyyy-MM-dd HH:mm:ss.fff}, {reader.GetValue(1)}, {reader.GetValue(2)}, {reader.GetValue(3)}, {reader.GetValue(4)}, {System.Text.Encoding.UTF8.GetString((byte[]) reader.GetValue(5))}"); - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e); - throw; - } - } - } - } -} -``` - - - - -* 连接参数与[建立连接](#建立连接)中的连接参数一致。 -* TDengineParameter 的 name 需要以 @ 开头,如 @0、@1、@2 等,value 需要 C# 列类型与 TDengine 列类型一一对应,具体对应关系请参考 [TDengine DataType 和 C# DataType](#tdengine-datatype-和-c-datatype)。 - -### 更多示例程序 - -[示例程序](https://github.com/taosdata/taos-connector-dotnet/tree/3.0/examples) - ## API 参考 ### ADO.NET 驱动 @@ -1781,14 +643,14 @@ C# 驱动提供了符合 ADO.NET 标准的 `DbDataReader` 接口,提供了用 创建消费者支持属性列表: -- `useSSL`:是否使用 SSL 连接,默认为 false -- `token`:连接 TDengine cloud 的 token -- `ws.message.enableCompression`:是否启用 WebSocket 压缩,默认为 false -- `ws.autoReconnect`:是否自动重连,默认为 false -- `ws.reconnect.retry.count`:重连次数,默认为 3 -- `ws.reconnect.interval.ms`:重连间隔毫秒时间,默认为 2000 +- `useSSL`:是否使用 SSL 连接,默认为 false。 +- `token`:连接 TDengine cloud 的 token。 +- `ws.message.enableCompression`:是否启用 WebSocket 压缩,默认为 false。 +- `ws.autoReconnect`:是否自动重连,默认为 false。 +- `ws.reconnect.retry.count`:重连次数,默认为 3。 +- `ws.reconnect.interval.ms`:重连间隔毫秒时间,默认为 2000。 -其他参数请参考:[Consumer 参数列表](../../develop/tmq/#数据订阅相关参数), 注意TDengine服务端自 3.2.0.0 版本开始消息订阅中的 auto.offset.reset 默认值发生变化。 +其他参数请参考:[Consumer 参数列表](../../../develop/tmq/#创建参数), 注意TDengine服务端自 3.2.0.0 版本开始消息订阅中的 auto.offset.reset 默认值发生变化。 - `public IConsumer Build()` - **接口说明**:构建消费者。 @@ -1944,4 +806,8 @@ ReferenceDeserializer 用来将消费到的一条记录反序列化为一个对 DictionaryDeserializer 则会将消费到的一行数据反序列化为一个 `Dictionary` 对象,其 key 为列名,值为对象。 -ReferenceDeserializer 和 DictionaryDeserializer 的接口不会被用户直接调用,请参考使用样例。 \ No newline at end of file +ReferenceDeserializer 和 DictionaryDeserializer 的接口不会被用户直接调用,请参考使用样例。 + +## 附录 + +[更多示例程序](https://github.com/taosdata/taos-connector-dotnet/tree/3.0/examples)。 \ No newline at end of file