Home

Awesome

Go Connector for TDengine

Build Status

English | 简体中文

[TDengine] provides Go database/sql driver as [taosSql][driver-go].

Remind

v2 is not compatible with v3 version and corresponds to the TDengine version as follows:

driver-go versionTDengine versionmajor features
v3.5.83.3.2.0+ / 3.1.2.0+fix null pointer exception
v3.5.73.3.2.0+ / 3.1.2.0+taosWS and taosRestful support request id
v3.5.63.3.2.0+ / 3.1.2.0+WebSocket performance improvements
v3.5.53.2.3.0+ / 3.1.1.27+support skip http ssl check
v3.5.43.2.3.0+ / 3.1.1.27+compatible with TDengine 3.3.0.0 tmq raw data
v3.5.33.2.3.0+ / 3.1.1.27+refactor taosWS
v3.5.23.2.3.0+ / 3.1.1.27+websocket compression and optimize tmq poll
v3.5.13.2.1.0+ / 3.1.1.13+native stmt query and geometry support
v3.5.03.0.5.0+tmq: get assignment and seek offset
v3.3.13.0.4.1+schemaless insert over websocket
v3.1.03.0.2.2+provide tmq apis close to kafka
v3.0.43.0.2.2+add request id
v3.0.33.0.1.5+statement insert over websocket
v3.0.23.0.1.5+bulk pulling over websocket
v3.0.13.0.0.0+tmq over websocket
v3.0.03.0.0.0+adapt to TDengine 3.0 query and insert

Install

Go 1.14+ is highly recommended for newly created projects.

go mod init taos-demo

import taosSql:

import (
    "database/sql"
    _ "github.com/taosdata/driver-go/v3/taosSql"
)

Use go mod for module management:

go mod tidy

Or go get to directly install it:

go get github.com/taosdata/driver-go/v3/taosSql

Usage

database/sql Standard

A simple use case:

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "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
    }
    defer taos.Close()
    taos.Exec("create database if not exists test")
    taos.Exec("use test")
    taos.Exec("create table if not exists tb1 (ts timestamp, a int)")
    _, err = taos.Exec("insert into tb1 values(now, 0)(now+1s,1)(now+2s,2)(now+3s,3)")
    if err != nil {
        fmt.Println("failed to insert, err:", err)
        return
    }
    rows, err := taos.Query("select * from tb1")
    if err != nil {
        fmt.Println("failed to select from table, err:", err)
        return
    }

    defer rows.Close()
    for rows.Next() {
        var r struct {
            ts time.Time
            a  int
        }
        err := rows.Scan(&r.ts, &r.a)
        if err != nil {
            fmt.Println("scan error:\n", err)
            return
        }
        fmt.Println(r.ts, r.a)
    }
}

APIs that are worthy to have a check:

Subscription

Create consumer:

func NewConsumer(conf *tmq.ConfigMap) (*Consumer, error)

Subscribe single topic:

func (c *Consumer) Subscribe(topic string, rebalanceCb RebalanceCb) error

Subscribe topics:

func (c *Consumer) SubscribeTopics(topics []string, rebalanceCb RebalanceCb) error

Poll message:

func (c *Consumer) Poll(timeoutMs int) tmq.Event

Commit message:

func (c *Consumer) Commit() ([]tmq.TopicPartition, error)

Get assignment:

func (c *Consumer) Assignment() (partitions []tmq.TopicPartition, err error)

Seek offset:

func (c *Consumer) Seek(partition tmq.TopicPartition, ignoredTimeoutMs int) error

Unsubscribe:

func (c *Consumer) Unsubscribe() error

Close consumer:

func (c *Consumer) Close() error

Example code: examples/tmq/main.go.

schemaless

InfluxDB format:

func (conn *Connector) InfluxDBInsertLines(lines []string, precision string) error

Example code: examples/schemaless/influx/main.go.

OpenTSDB telnet format:

func (conn *Connector) OpenTSDBInsertTelnetLines(lines []string) error

Example code: examples/schemaless/telnet/main.go.

OpenTSDB json format:

func (conn *Connector) OpenTSDBInsertJsonPayload(payload string) error

Example code: examples/schemaless/json/main.go.

stmt insert

Prepare sql:

func (stmt *InsertStmt) Prepare(sql string) error

Set the child table name:

func (stmt *InsertStmt) SetSubTableName(name string) error

Set the table name:

func (stmt *InsertStmt) SetTableName(name string) error

Set the subtable name and tags:

func (stmt *InsertStmt) SetTableNameWithTags(tableName string, tags *param.Param) error

Bind parameters:

func (stmt *InsertStmt) BindParam(params []*param.Param, bindType *param.ColumnType) error

Add batch:

func (stmt *InsertStmt) AddBatch() error

implement:

func (stmt *InsertStmt) Execute() error

Get the number of affected rows:

func (stmt *InsertStmt) GetAffectedRows() int

Close stmt:

func (stmt *InsertStmt) Close() error

Example code: examples/stmtinsert/main.go.

restful implementation of the database/sql standard interface

A simple use case:

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "github.com/taosdata/driver-go/v3/taosRestful"
)

func main() {
    var taosDSN = "root:taosdata@http(localhost:6041)/"
    taos, err := sql.Open("taosRestful", taosDSN)
    if err != nil {
        fmt.Println("failed to connect TDengine, err:", err)
        return
    }
    defer taos.Close()
    taos.Exec("create database if not exists test")
    taos.Exec("create table if not exists test.tb1 (ts timestamp, a int)")
    _, err = taos.Exec("insert into test.tb1 values(now, 0)(now+1s,1)(now+2s,2)(now+3s,3)")
    if err != nil {
        fmt.Println("failed to insert, err:", err)
        return
    }
    rows, err := taos.Query("select * from test.tb1")
    if err != nil {
        fmt.Println("failed to select from table, err:", err)
        return
    }

    defer rows.Close()
    for rows.Next() {
        var r struct {
            ts time.Time
            a  int
        }
        err := rows.Scan(&r.ts, &r.a)
        if err != nil {
            fmt.Println("scan error:\n", err)
            return
        }
        fmt.Println(r.ts, r.a)
    }
}

Usage of taosRestful

import

import (
    "database/sql"
    _ "github.com/taosdata/driver-go/v3/taosRestful"
)

The driverName of sql.Open is taosRestful

The DSN format is:

database username:database password@connection-method(domain or ip:port)/[database][? Parameter]

Example:

root:taosdata@http(localhost:6041)/test?readBufferSize=52428800

Parameters:

Usage restrictions

Since the restful interface is stateless, the use db syntax will not work, you need to put the db name into the sql statement, e.g. create table if not exists tb1 (ts timestamp, a int) to create table if not exists test.tb1 (ts timestamp, a int) otherwise it will report an error [0x217] Database not specified or available.

You can also put the db name in the DSN by changing root:taosdata@http(localhost:6041)/ to root:taosdata@http(localhost:6041)/test. Executing the create database statement when the specified db does not exist will not report an error, while executing other queries or inserts will report an error. The example is as follows:

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "github.com/taosdata/driver-go/v3/taosRestful"
)

func main() {
    var taosDSN = "root:taosdata@http(localhost:6041)/test"
    taos, err := sql.Open("taosRestful", taosDSN)
    if err != nil {
        fmt.Println("failed to connect TDengine, err:", err)
        return
    }
    defer taos.Close()
    taos.Exec("create database if not exists test")
    taos.Exec("create table if not exists tb1 (ts timestamp, a int)")
    _, err = taos.Exec("insert into tb1 values(now, 0)(now+1s,1)(now+2s,2)(now+3s,3)")
    if err != nil {
        fmt.Println("failed to insert, err:", err)
        return
    }
    rows, err := taos.Query("select * from tb1")
    if err != nil {
        fmt.Println("failed to select from table, err:", err)
        return
    }

    defer rows.Close()
    for rows.Next() {
        var r struct {
            ts time.Time
            a  int
        }
        err := rows.Scan(&r.ts, &r.a)
        if err != nil {
            fmt.Println("scan error:\n", err)
            return
        }
        fmt.Println(r.ts, r.a)
    }
}

websocket implementation of the database/sql standard interface

A simple use case:

package main

import (
    "database/sql"
    "fmt"
    "time"

    _ "github.com/taosdata/driver-go/v3/taosWS"
)

func main() {
    var taosDSN = "root:taosdata@ws(localhost:6041)/"
    taos, err := sql.Open("taosWS", taosDSN)
    if err != nil {
        fmt.Println("failed to connect TDengine, err:", err)
        return
    }
    defer taos.Close()
    taos.Exec("create database if not exists test")
    taos.Exec("create table if not exists test.tb1 (ts timestamp, a int)")
    _, err = taos.Exec("insert into test.tb1 values(now, 0)(now+1s,1)(now+2s,2)(now+3s,3)")
    if err != nil {
        fmt.Println("failed to insert, err:", err)
        return
    }
    rows, err := taos.Query("select * from test.tb1")
    if err != nil {
        fmt.Println("failed to select from table, err:", err)
        return
    }

    defer rows.Close()
    for rows.Next() {
        var r struct {
            ts time.Time
            a  int
        }
        err := rows.Scan(&r.ts, &r.a)
        if err != nil {
            fmt.Println("scan error:\n", err)
            return
        }
        fmt.Println(r.ts, r.a)
    }
}

Usage of websocket

import

import (
    "database/sql"
    _ "github.com/taosdata/driver-go/v3/taosWS"
)

The driverName of sql.Open is taosWS

The DSN format is:

database username:database password@connection-method(domain or ip:port)/[database][? parameter]

Example:

root:taosdata@ws(localhost:6041)/test?writeTimeout=10s&readTimeout=10m

Parameters:

Using tmq over websocket

Use tmq over websocket. The server needs to start taoAdapter.

Configure related API

Create a configuration, pass in the websocket address and the length of the sending channel.

Set username.

Set password.

Set the client ID.

Set the subscription group ID.

Set the waiting time for sending messages.

Set the message timeout.

Set the error handler.

Set the close handler.

Subscription related API

Create a consumer.

Subscribe a topic.

Subscribe to topics.

Poll messages.

Commit message.

Get assignment.

Seek offset.

Close the connection.

Example code: examples/tmqoverws/main.go.

Parameter binding via WebSocket

Use stmt via websocket. The server needs to start taoAdapter.

Configure related API

Parameter binding related API

For a complete example of parameter binding, see GitHub example file

Directory structure

driver-go
├── af //advanced function
├── common //common function and constants
├── errors // error type
├── examples //examples
├── taosRestful // database operation standard interface (restful)
├── taosSql // database operation standard interface
├── types // inner type
├── wrapper // cgo wrapper
└── ws // websocket

Link

driver-go: https://github.com/taosdata/driver-go

TDengine: https://github.com/taosdata/TDengine