diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000000000000000000000000000000000..35aea3658b464000a4132a6b4a83df286d0f4933 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "src/connector/go"] + path = src/connector/go + url = https://github.com/taosdata/driver-go diff --git a/src/connector/go b/src/connector/go new file mode 160000 index 0000000000000000000000000000000000000000..8c58c512b6acda8bcdfa48fdc7140227b5221766 --- /dev/null +++ b/src/connector/go @@ -0,0 +1 @@ +Subproject commit 8c58c512b6acda8bcdfa48fdc7140227b5221766 diff --git a/src/connector/go/src/taosSql/connection.go b/src/connector/go/src/taosSql/connection.go deleted file mode 100755 index 2a3f5a9acd8ca9ea384d5bb0f081dc9495f7fd13..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/connection.go +++ /dev/null @@ -1,368 +0,0 @@ -/* - * 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 . - */ - -package taosSql - -import "C" -import ( - "context" - "errors" - "database/sql/driver" - "unsafe" - "strconv" - "strings" - "time" -) - -type taosConn struct { - taos unsafe.Pointer - affectedRows int - insertId int - cfg *config - status statusFlag - parseTime bool - reset bool // set when the Go SQL package calls ResetSession -} - -type taosSqlResult struct { - affectedRows int64 - insertId int64 -} - -func (res *taosSqlResult) LastInsertId() (int64, error) { - return res.insertId, nil -} - -func (res *taosSqlResult) RowsAffected() (int64, error) { - return res.affectedRows, nil -} - -func (mc *taosConn) Begin() (driver.Tx, error) { - taosLog.Println("taosSql not support transaction") - return nil, errors.New("taosSql not support transaction") -} - -func (mc *taosConn) Close() (err error) { - if mc.taos == nil { - return errConnNoExist - } - mc.taos_close() - return nil -} - -func (mc *taosConn) Prepare(query string) (driver.Stmt, error) { - if mc.taos == nil { - return nil, errInvalidConn - } - - stmt := &taosSqlStmt{ - mc: mc, - pSql: query, - } - - // find ? count and save to stmt.paramCount - stmt.paramCount = strings.Count(query, "?") - - //fmt.Printf("prepare alloc stmt:%p, sql:%s\n", stmt, query) - taosLog.Printf("prepare alloc stmt:%p, sql:%s\n", stmt, query) - - return stmt, nil -} - -func (mc *taosConn) interpolateParams(query string, args []driver.Value) (string, error) { - // Number of ? should be same to len(args) - if strings.Count(query, "?") != len(args) { - return "", driver.ErrSkip - } - - buf := make([]byte, defaultBufSize) - buf = buf[:0] // clear buf - argPos := 0 - - for i := 0; i < len(query); i++ { - q := strings.IndexByte(query[i:], '?') - if q == -1 { - buf = append(buf, query[i:]...) - break - } - buf = append(buf, query[i:i+q]...) - i += q - - arg := args[argPos] - argPos++ - - if arg == nil { - buf = append(buf, "NULL"...) - continue - } - - switch v := arg.(type) { - case int64: - buf = strconv.AppendInt(buf, v, 10) - case uint64: - // Handle uint64 explicitly because our custom ConvertValue emits unsigned values - buf = strconv.AppendUint(buf, v, 10) - case float64: - buf = strconv.AppendFloat(buf, v, 'g', -1, 64) - case bool: - if v { - buf = append(buf, '1') - } else { - buf = append(buf, '0') - } - case time.Time: - if v.IsZero() { - buf = append(buf, "'0000-00-00'"...) - } else { - v := v.In(mc.cfg.loc) - v = v.Add(time.Nanosecond * 500) // To round under microsecond - year := v.Year() - year100 := year / 100 - year1 := year % 100 - month := v.Month() - day := v.Day() - hour := v.Hour() - minute := v.Minute() - second := v.Second() - micro := v.Nanosecond() / 1000 - - buf = append(buf, []byte{ - '\'', - digits10[year100], digits01[year100], - digits10[year1], digits01[year1], - '-', - digits10[month], digits01[month], - '-', - digits10[day], digits01[day], - ' ', - digits10[hour], digits01[hour], - ':', - digits10[minute], digits01[minute], - ':', - digits10[second], digits01[second], - }...) - - if micro != 0 { - micro10000 := micro / 10000 - micro100 := micro / 100 % 100 - micro1 := micro % 100 - buf = append(buf, []byte{ - '.', - digits10[micro10000], digits01[micro10000], - digits10[micro100], digits01[micro100], - digits10[micro1], digits01[micro1], - }...) - } - buf = append(buf, '\'') - } - case []byte: - if v == nil { - buf = append(buf, "NULL"...) - } else { - buf = append(buf, "_binary'"...) - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeBytesBackslash(buf, v) - } else { - buf = escapeBytesQuotes(buf, v) - } - buf = append(buf, '\'') - } - case string: - //buf = append(buf, '\'') - if mc.status&statusNoBackslashEscapes == 0 { - buf = escapeStringBackslash(buf, v) - } else { - buf = escapeStringQuotes(buf, v) - } - //buf = append(buf, '\'') - default: - return "", driver.ErrSkip - } - - //if len(buf)+4 > mc.maxAllowedPacket { - if len(buf)+4 > maxTaosSqlLen { - return "", driver.ErrSkip - } - } - if argPos != len(args) { - return "", driver.ErrSkip - } - return string(buf), nil -} - -func (mc *taosConn) Exec(query string, args []driver.Value) (driver.Result, error) { - if mc.taos == nil { - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.interpolateParams { - return nil, driver.ErrSkip - } - // try to interpolate the parameters to save extra roundtrips for preparing and closing a statement - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - - mc.affectedRows = 0 - mc.insertId = 0 - _, err := mc.taosQuery(query) - if err == nil { - return &taosSqlResult{ - affectedRows: int64(mc.affectedRows), - insertId: int64(mc.insertId), - }, err - } - - return nil, err -} - -func (mc *taosConn) Query(query string, args []driver.Value) (driver.Rows, error) { - return mc.query(query, args) -} - -func (mc *taosConn) query(query string, args []driver.Value) (*textRows, error) { - if mc.taos == nil { - return nil, driver.ErrBadConn - } - if len(args) != 0 { - if !mc.cfg.interpolateParams { - return nil, driver.ErrSkip - } - // try client-side prepare to reduce roundtrip - prepared, err := mc.interpolateParams(query, args) - if err != nil { - return nil, err - } - query = prepared - } - - num_fields, err := mc.taosQuery(query) - if err == nil { - // Read Result - rows := new(textRows) - rows.mc = mc - - // Columns field - rows.rs.columns, err = mc.readColumns(num_fields) - return rows, err - } - return nil, err -} - -// Ping implements driver.Pinger interface -func (mc *taosConn) Ping(ctx context.Context) (err error) { - if mc.taos != nil { - return nil - } - return errInvalidConn -} - -// BeginTx implements driver.ConnBeginTx interface -func (mc *taosConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - taosLog.Println("taosSql not support transaction") - return nil, errors.New("taosSql not support transaction") -} - -func (mc *taosConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - if mc.taos == nil { - return nil, errInvalidConn - } - - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - rows, err := mc.query(query, dargs) - if err != nil { - return nil, err - } - - return rows, err -} - -func (mc *taosConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - if mc.taos == nil { - return nil, errInvalidConn - } - - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - return mc.Exec(query, dargs) -} - -func (mc *taosConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if mc.taos == nil { - return nil, errInvalidConn - } - - stmt, err := mc.Prepare(query) - if err != nil { - return nil, err - } - - return stmt, nil -} - -func (stmt *taosSqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - if stmt.mc == nil { - return nil, errInvalidConn - } - dargs, err := namedValueToValue(args) - - if err != nil { - return nil, err - } - - rows, err := stmt.query(dargs) - if err != nil { - return nil, err - } - return rows, err -} - -func (stmt *taosSqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - if stmt.mc == nil { - return nil, errInvalidConn - } - - dargs, err := namedValueToValue(args) - if err != nil { - return nil, err - } - - return stmt.Exec(dargs) -} - -func (mc *taosConn) CheckNamedValue(nv *driver.NamedValue) (err error) { - nv.Value, err = converter{}.ConvertValue(nv.Value) - return -} - -// ResetSession implements driver.SessionResetter. -// (From Go 1.10) -func (mc *taosConn) ResetSession(ctx context.Context) error { - if mc.taos == nil { - return driver.ErrBadConn - } - mc.reset = true - return nil -} diff --git a/src/connector/go/src/taosSql/connector.go b/src/connector/go/src/taosSql/connector.go deleted file mode 100755 index 55715b949ede42de59bae0ac229b26ef579faba7..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/connector.go +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 . - */ -package taosSql - -import ( - "context" - "database/sql/driver" -) - -type connector struct { - cfg *config -} - -// Connect implements driver.Connector interface. -// Connect returns a connection to the database. -func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { - var err error - // New taosConn - mc := &taosConn{ - cfg: c.cfg, - parseTime: c.cfg.parseTime, - } - - // Connect to Server - mc.taos, err = mc.taosConnect(mc.cfg.addr, mc.cfg.user, mc.cfg.passwd, mc.cfg.dbName, mc.cfg.port) - if err != nil { - return nil, err - } - - return mc, nil -} - -// Driver implements driver.Connector interface. -// Driver returns &taosSQLDriver{}. -func (c *connector) Driver() driver.Driver { - return &taosSQLDriver{} -} diff --git a/src/connector/go/src/taosSql/const.go b/src/connector/go/src/taosSql/const.go deleted file mode 100755 index 89214a0d45c5620d8b865bdc7afad45f2130b95b..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/const.go +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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 . - */ - -package taosSql - -const ( - timeFormat = "2006-01-02 15:04:05" - maxTaosSqlLen = 65380 - defaultBufSize = maxTaosSqlLen + 32 -) - -type fieldType byte - -type fieldFlag uint16 - -const ( - flagNotNULL fieldFlag = 1 << iota -) - -type statusFlag uint16 - -const ( - statusInTrans statusFlag = 1 << iota - statusInAutocommit - statusReserved // Not in documentation - statusMoreResultsExists - statusNoGoodIndexUsed - statusNoIndexUsed - statusCursorExists - statusLastRowSent - statusDbDropped - statusNoBackslashEscapes - statusMetadataChanged - statusQueryWasSlow - statusPsOutParams - statusInTransReadonly - statusSessionStateChanged -) - diff --git a/src/connector/go/src/taosSql/driver.go b/src/connector/go/src/taosSql/driver.go deleted file mode 100755 index 6839979c61c1ede15ea95c9a1f9c570b84316de0..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/driver.go +++ /dev/null @@ -1,43 +0,0 @@ -/* - * 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 . - */ -package taosSql - -import ( - "context" - "database/sql" - "database/sql/driver" -) - -// taosSqlDriver is exported to make the driver directly accessible. -// In general the driver is used via the database/sql package. -type taosSQLDriver struct{} - -// Open new Connection. -// the DSN string is formatted -func (d taosSQLDriver) Open(dsn string) (driver.Conn, error) { - cfg, err := parseDSN(dsn) - if err != nil { - return nil, err - } - c := &connector{ - cfg: cfg, - } - return c.Connect(context.Background()) -} - -func init() { - sql.Register("taosSql", &taosSQLDriver{}) - taosLogInit() -} diff --git a/src/connector/go/src/taosSql/dsn.go b/src/connector/go/src/taosSql/dsn.go deleted file mode 100755 index c68ae1725cb730c770325a1b3603416b8c2ac1f6..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/dsn.go +++ /dev/null @@ -1,202 +0,0 @@ -/* - * 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 . - */ - -package taosSql - -import ( - "errors" - "net/url" - "strconv" - "strings" - "time" -) - -var ( - errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?") - errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)") - errInvalidDSNPort = errors.New("invalid DSN: network port is not a valid number") - errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name") -) - -// Config is a configuration parsed from a DSN string. -// If a new Config is created instead of being parsed from a DSN string, -// the NewConfig function should be used, which sets default values. -type config struct { - user string // Username - passwd string // Password (requires User) - net string // Network type - addr string // Network address (requires Net) - port int - dbName string // Database name - params map[string]string // Connection parameters - loc *time.Location // Location for time.Time values - columnsWithAlias bool // Prepend table alias to column names - interpolateParams bool // Interpolate placeholders into query string - parseTime bool // Parse time values to time.Time -} - -// NewConfig creates a new Config and sets default values. -func newConfig() *config { - return &config{ - loc: time.UTC, - interpolateParams: true, - parseTime: true, - } -} - -// ParseDSN parses the DSN string to a Config -func parseDSN(dsn string) (cfg *config, err error) { - taosLog.Println("input dsn:", dsn) - - // New config with some default values - cfg = newConfig() - - // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] - // Find the last '/' (since the password or the net addr might contain a '/') - foundSlash := false - for i := len(dsn) - 1; i >= 0; i-- { - if dsn[i] == '/' { - foundSlash = true - var j, k int - - // left part is empty if i <= 0 - if i > 0 { - // [username[:password]@][protocol[(address)]] - // Find the last '@' in dsn[:i] - for j = i; j >= 0; j-- { - if dsn[j] == '@' { - // username[:password] - // Find the first ':' in dsn[:j] - for k = 0; k < j; k++ { - if dsn[k] == ':' { - cfg.passwd = dsn[k+1 : j] - break - } - } - cfg.user = dsn[:k] - - break - } - } - - // [protocol[(address)]] - // Find the first '(' in dsn[j+1:i] - for k = j + 1; k < i; k++ { - if dsn[k] == '(' { - // dsn[i-1] must be == ')' if an address is specified - if dsn[i-1] != ')' { - if strings.ContainsRune(dsn[k+1:i], ')') { - return nil, errInvalidDSNUnescaped - } - return nil, errInvalidDSNAddr - } - strs := strings.Split(dsn[k+1:i-1], ":") - if len(strs) == 1 { - return nil, errInvalidDSNAddr - } - cfg.addr = strs[0] - cfg.port, err = strconv.Atoi(strs[1]) - if err != nil { - return nil, errInvalidDSNPort - } - break - } - } - cfg.net = dsn[j+1 : k] - } - - // dbname[?param1=value1&...¶mN=valueN] - // Find the first '?' in dsn[i+1:] - for j = i + 1; j < len(dsn); j++ { - if dsn[j] == '?' { - if err = parseDSNParams(cfg, dsn[j+1:]); err != nil { - return - } - break - } - } - cfg.dbName = dsn[i+1 : j] - - break - } - } - - if !foundSlash && len(dsn) > 0 { - return nil, errInvalidDSNNoSlash - } - - taosLog.Printf("cfg info: %+v", cfg) - - return -} - -// parseDSNParams parses the DSN "query string" -// Values must be url.QueryEscape'ed -func parseDSNParams(cfg *config, params string) (err error) { - for _, v := range strings.Split(params, "&") { - param := strings.SplitN(v, "=", 2) - if len(param) != 2 { - continue - } - - // cfg params - switch value := param[1]; param[0] { - case "columnsWithAlias": - var isBool bool - cfg.columnsWithAlias, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Enable client side placeholder substitution - case "interpolateParams": - var isBool bool - cfg.interpolateParams, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - // Time Location - case "loc": - if value, err = url.QueryUnescape(value); err != nil { - return - } - cfg.loc, err = time.LoadLocation(value) - if err != nil { - return - } - - // time.Time parsing - case "parseTime": - var isBool bool - cfg.parseTime, isBool = readBool(value) - if !isBool { - return errors.New("invalid bool value: " + value) - } - - default: - // lazy init - if cfg.params == nil { - cfg.params = make(map[string]string) - } - - if cfg.params[param[0]], err = url.QueryUnescape(value); err != nil { - return - } - } - } - - return -} diff --git a/src/connector/go/src/taosSql/result.go b/src/connector/go/src/taosSql/result.go deleted file mode 100755 index 2367560c31d06f56ac27c20d4a5a5aa099051077..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/result.go +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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 . - */ -package taosSql - -/* -#cgo CFLAGS : -I/usr/include -#cgo LDFLAGS: -L/usr/lib -ltaos -#include -#include -#include -#include -*/ -import "C" - -import ( - "database/sql/driver" - "errors" - "fmt" - "io" - "strconv" - "time" - "unsafe" -) - -/****************************************************************************** -* Result * -******************************************************************************/ -// Read Packets as Field Packets until EOF-Packet or an Error appears -func (mc *taosConn) readColumns(count int) ([]taosSqlField, error) { - - columns := make([]taosSqlField, count) - var result unsafe.Pointer - result = C.taos_use_result(mc.taos) - if result == nil { - return nil, errors.New("invalid result") - } - - pFields := (*C.struct_taosField)(C.taos_fetch_fields(result)) - - // TODO: Optimized rewriting !!!! - fields := (*[1 << 30]C.struct_taosField)(unsafe.Pointer(pFields)) - - for i := 0; i < count; i++ { - //columns[i].tableName = ms.taos. - //fmt.Println(reflect.TypeOf(fields[i].name)) - var charray []byte - for j := range fields[i].name { - //fmt.Println("fields[i].name[j]: ", fields[i].name[j]) - if fields[i].name[j] != 0 { - charray = append(charray, byte(fields[i].name[j])) - } else { - break - } - } - columns[i].name = string(charray) - columns[i].length = (uint32)(fields[i].bytes) - columns[i].fieldType = fieldType(fields[i]._type) - columns[i].flags = 0 - // columns[i].decimals = 0 - //columns[i].charSet = 0 - } - return columns, nil -} - -func (rows *taosSqlRows) readRow(dest []driver.Value) error { - mc := rows.mc - - if rows.rs.done || mc == nil { - return io.EOF - } - - var result unsafe.Pointer - result = C.taos_use_result(mc.taos) - if result == nil { - return errors.New(C.GoString(C.taos_errstr(mc.taos))) - } - - //var row *unsafe.Pointer - row := C.taos_fetch_row(result) - if row == nil { - rows.rs.done = true - C.taos_free_result(result) - rows.mc = nil - return io.EOF - } - - // because sizeof(void*) == sizeof(int*) == 8 - // notes: sizeof(int) == 8 in go, but sizeof(int) == 4 in C. - for i := range dest { - currentRow := (unsafe.Pointer)(uintptr(*((*int)(unsafe.Pointer(uintptr(unsafe.Pointer(row)) + uintptr(i)*unsafe.Sizeof(int(0))))))) - - if currentRow == nil { - dest[i] = nil - continue - } - - switch rows.rs.columns[i].fieldType { - case C.TSDB_DATA_TYPE_BOOL: - if (*((*byte)(currentRow))) != 0 { - dest[i] = true - } else { - dest[i] = false - } - break - - case C.TSDB_DATA_TYPE_TINYINT: - dest[i] = (int)(*((*byte)(currentRow))) - break - - case C.TSDB_DATA_TYPE_SMALLINT: - dest[i] = (int16)(*((*int16)(currentRow))) - break - - case C.TSDB_DATA_TYPE_INT: - dest[i] = (int)(*((*int32)(currentRow))) // notes int32 of go <----> int of C - break - - case C.TSDB_DATA_TYPE_BIGINT: - dest[i] = (int64)(*((*int64)(currentRow))) - break - - case C.TSDB_DATA_TYPE_FLOAT: - dest[i] = (*((*float32)(currentRow))) - break - - case C.TSDB_DATA_TYPE_DOUBLE: - dest[i] = (*((*float64)(currentRow))) - break - - case C.TSDB_DATA_TYPE_BINARY, C.TSDB_DATA_TYPE_NCHAR: - charLen := rows.rs.columns[i].length - var index uint32 - binaryVal := make([]byte, charLen) - for index = 0; index < charLen; index++ { - binaryVal[index] = *((*byte)(unsafe.Pointer(uintptr(currentRow) + uintptr(index)))) - } - dest[i] = string(binaryVal[:]) - break - - case C.TSDB_DATA_TYPE_TIMESTAMP: - if mc.cfg.parseTime == true { - timestamp := (int64)(*((*int64)(currentRow))) - dest[i] = timestampConvertToString(timestamp, int(C.taos_result_precision(result))) - } else { - dest[i] = (int64)(*((*int64)(currentRow))) - } - break - - default: - fmt.Println("default fieldType: set dest[] to nil") - dest[i] = nil - break - } - } - - return nil -} - -// Read result as Field format until all rows or an Error appears -// call this func in conn mode -func (rows *textRows) readRow(dest []driver.Value) error { - return rows.taosSqlRows.readRow(dest) -} - -// call thsi func in stmt mode -func (rows *binaryRows) readRow(dest []driver.Value) error { - return rows.taosSqlRows.readRow(dest) -} - -func timestampConvertToString(timestamp int64, precision int) string { - var decimal, sVal, nsVal int64 - if precision == 0 { - decimal = timestamp % 1000 - sVal = timestamp / 1000 - nsVal = decimal * 1000 - } else { - decimal = timestamp % 1000000 - sVal = timestamp / 1000000 - nsVal = decimal * 1000000 - } - - date_time := time.Unix(sVal, nsVal) - - //const base_format = "2006-01-02 15:04:05" - str_time := date_time.Format(timeFormat) - - return (str_time + "." + strconv.Itoa(int(decimal))) -} diff --git a/src/connector/go/src/taosSql/rows.go b/src/connector/go/src/taosSql/rows.go deleted file mode 100755 index 5040dca06d205865379e21d45e5d5dd3e2b793db..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/rows.go +++ /dev/null @@ -1,296 +0,0 @@ -/* - * 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 . - */ -package taosSql -/* -#cgo CFLAGS : -I/usr/include -#cgo LDFLAGS: -L/usr/lib -ltaos -#include -#include -#include -#include -*/ -import "C" - -import ( - "database/sql" - "database/sql/driver" - "io" - "math" - "reflect" -) - -type taosSqlField struct { - tableName string - name string - length uint32 - flags fieldFlag // indicate whether this field can is null - fieldType fieldType - decimals byte - charSet uint8 -} - -type resultSet struct { - columns []taosSqlField - columnNames []string - done bool -} - -type taosSqlRows struct { - mc *taosConn - rs resultSet -} - -type binaryRows struct { - taosSqlRows -} - -type textRows struct { - taosSqlRows -} - -func (rows *taosSqlRows) Columns() []string { - if rows.rs.columnNames != nil { - return rows.rs.columnNames - } - - columns := make([]string, len(rows.rs.columns)) - if rows.mc != nil && rows.mc.cfg.columnsWithAlias { - for i := range columns { - if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { - columns[i] = tableName + "." + rows.rs.columns[i].name - } else { - columns[i] = rows.rs.columns[i].name - } - } - } else { - for i := range columns { - columns[i] = rows.rs.columns[i].name - } - } - - rows.rs.columnNames = columns - - return columns -} - -func (rows *taosSqlRows) ColumnTypeDatabaseTypeName(i int) string { - return rows.rs.columns[i].typeDatabaseName() -} - -func (rows *taosSqlRows) ColumnTypeLength(i int) (length int64, ok bool) { - return int64(rows.rs.columns[i].length), true -} - -func (rows *taosSqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { - return rows.rs.columns[i].flags&flagNotNULL == 0, true -} - -func (rows *taosSqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { - column := rows.rs.columns[i] - decimals := int64(column.decimals) - - switch column.fieldType { - case C.TSDB_DATA_TYPE_FLOAT: - fallthrough - case C.TSDB_DATA_TYPE_DOUBLE: - if decimals == 0x1f { - return math.MaxInt64, math.MaxInt64, true - } - return math.MaxInt64, decimals, true - } - - return 0, 0, false -} - -func (rows *taosSqlRows) ColumnTypeScanType(i int) reflect.Type { - return rows.rs.columns[i].scanType() -} - -func (rows *taosSqlRows) Close() error { - if rows.mc != nil { - result := C.taos_use_result(rows.mc.taos) - if result != nil { - C.taos_free_result(result) - } - rows.mc = nil - } - return nil -} - -func (rows *taosSqlRows) HasNextResultSet() (b bool) { - if rows.mc == nil { - return false - } - return rows.mc.status&statusMoreResultsExists != 0 -} - -func (rows *taosSqlRows) nextResultSet() (int, error) { - if rows.mc == nil { - return 0, io.EOF - } - - // Remove unread packets from stream - if !rows.rs.done { - rows.rs.done = true - } - - if !rows.HasNextResultSet() { - rows.mc = nil - return 0, io.EOF - } - rows.rs = resultSet{} - return 0,nil -} - -func (rows *taosSqlRows) nextNotEmptyResultSet() (int, error) { - for { - resLen, err := rows.nextResultSet() - if err != nil { - return 0, err - } - - if resLen > 0 { - return resLen, nil - } - - rows.rs.done = true - } -} - -func (rows *binaryRows) NextResultSet() error { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -// stmt.Query return binary rows, and get row from this func -func (rows *binaryRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} - -func (rows *textRows) NextResultSet() (err error) { - resLen, err := rows.nextNotEmptyResultSet() - if err != nil { - return err - } - - rows.rs.columns, err = rows.mc.readColumns(resLen) - return err -} - -// db.Query return text rows, and get row from this func -func (rows *textRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - // Fetch next row from stream - return rows.readRow(dest) - } - return io.EOF -} - -func (mf *taosSqlField) typeDatabaseName() string { - //fmt.Println("######## (mf *taosSqlField) typeDatabaseName() mf.fieldType:", mf.fieldType) - switch mf.fieldType { - case C.TSDB_DATA_TYPE_BOOL: - return "BOOL" - - case C.TSDB_DATA_TYPE_TINYINT: - return "TINYINT" - - case C.TSDB_DATA_TYPE_SMALLINT: - return "SMALLINT" - - case C.TSDB_DATA_TYPE_INT: - return "INT" - - case C.TSDB_DATA_TYPE_BIGINT: - return "BIGINT" - - case C.TSDB_DATA_TYPE_FLOAT: - return "FLOAT" - - case C.TSDB_DATA_TYPE_DOUBLE: - return "DOUBLE" - - case C.TSDB_DATA_TYPE_BINARY: - return "BINARY" - - case C.TSDB_DATA_TYPE_NCHAR: - return "NCHAR" - - case C.TSDB_DATA_TYPE_TIMESTAMP: - return "TIMESTAMP" - - default: - return "" - } -} - -var ( - scanTypeFloat32 = reflect.TypeOf(float32(0)) - scanTypeFloat64 = reflect.TypeOf(float64(0)) - scanTypeInt8 = reflect.TypeOf(int8(0)) - scanTypeInt16 = reflect.TypeOf(int16(0)) - scanTypeInt32 = reflect.TypeOf(int32(0)) - scanTypeInt64 = reflect.TypeOf(int64(0)) - scanTypeNullTime = reflect.TypeOf(NullTime{}) - scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) - scanTypeUnknown = reflect.TypeOf(new(interface{})) -) - -func (mf *taosSqlField) scanType() reflect.Type { - //fmt.Println("######## (mf *taosSqlField) scanType() mf.fieldType:", mf.fieldType) - switch mf.fieldType { - case C.TSDB_DATA_TYPE_BOOL: - return scanTypeInt8 - - case C.TSDB_DATA_TYPE_TINYINT: - return scanTypeInt8 - - case C.TSDB_DATA_TYPE_SMALLINT: - return scanTypeInt16 - - case C.TSDB_DATA_TYPE_INT: - return scanTypeInt32 - - case C.TSDB_DATA_TYPE_BIGINT: - return scanTypeInt64 - - case C.TSDB_DATA_TYPE_FLOAT: - return scanTypeFloat32 - - case C.TSDB_DATA_TYPE_DOUBLE: - return scanTypeFloat64 - - case C.TSDB_DATA_TYPE_BINARY: - return scanTypeRawBytes - - case C.TSDB_DATA_TYPE_NCHAR: - return scanTypeRawBytes - - case C.TSDB_DATA_TYPE_TIMESTAMP: - return scanTypeNullTime - - default: - return scanTypeUnknown - } -} diff --git a/src/connector/go/src/taosSql/statement.go b/src/connector/go/src/taosSql/statement.go deleted file mode 100755 index 3aa3e01564553798510a4d30806b7ec5c5793ba9..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/statement.go +++ /dev/null @@ -1,158 +0,0 @@ -/* - * 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 . - */ -package taosSql - -import ( - "database/sql/driver" - "fmt" - "reflect" -) - -type taosSqlStmt struct { - mc *taosConn - id uint32 - pSql string - paramCount int -} - -func (stmt *taosSqlStmt) Close() error { - return nil -} - -func (stmt *taosSqlStmt) NumInput() int { - return stmt.paramCount -} - -func (stmt *taosSqlStmt) Exec(args []driver.Value) (driver.Result, error) { - if stmt.mc == nil || stmt.mc.taos == nil { - return nil, errInvalidConn - } - return stmt.mc.Exec(stmt.pSql, args) -} - -func (stmt *taosSqlStmt) Query(args []driver.Value) (driver.Rows, error) { - if stmt.mc == nil || stmt.mc.taos == nil { - return nil, errInvalidConn - } - return stmt.query(args) -} - -func (stmt *taosSqlStmt) query(args []driver.Value) (*binaryRows, error) { - mc := stmt.mc - if mc == nil || mc.taos == nil { - return nil, errInvalidConn - } - - querySql := stmt.pSql - - if len(args) != 0 { - if !mc.cfg.interpolateParams { - return nil, driver.ErrSkip - } - // try client-side prepare to reduce roundtrip - prepared, err := mc.interpolateParams(stmt.pSql, args) - if err != nil { - return nil, err - } - querySql = prepared - } - - num_fields, err := mc.taosQuery(querySql) - if err == nil { - // Read Result - rows := new(binaryRows) - rows.mc = mc - // Columns field - rows.rs.columns, err = mc.readColumns(num_fields) - return rows, err - } - return nil, err -} - -type converter struct{} - -// ConvertValue mirrors the reference/default converter in database/sql/driver -// with _one_ exception. We support uint64 with their high bit and the default -// implementation does not. This function should be kept in sync with -// database/sql/driver defaultConverter.ConvertValue() except for that -// deliberate difference. -func (c converter) ConvertValue(v interface{}) (driver.Value, error) { - - if driver.IsValue(v) { - return v, nil - } - - if vr, ok := v.(driver.Valuer); ok { - sv, err := callValuerValue(vr) - if err != nil { - return nil, err - } - if !driver.IsValue(sv) { - return nil, fmt.Errorf("non-Value type %T returned from Value", sv) - } - - return sv, nil - } - - rv := reflect.ValueOf(v) - switch rv.Kind() { - case reflect.Ptr: - // indirect pointers - if rv.IsNil() { - return nil, nil - } else { - return c.ConvertValue(rv.Elem().Interface()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return rv.Int(), nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return rv.Uint(), nil - case reflect.Float32, reflect.Float64: - return rv.Float(), nil - case reflect.Bool: - return rv.Bool(), nil - case reflect.Slice: - ek := rv.Type().Elem().Kind() - if ek == reflect.Uint8 { - return rv.Bytes(), nil - } - return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) - case reflect.String: - return rv.String(), nil - } - return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) -} - -var valuerReflectType = reflect.TypeOf((*driver.Valuer)(nil)).Elem() - -// callValuerValue returns vr.Value(), with one exception: -// If vr.Value is an auto-generated method on a pointer type and the -// pointer is nil, it would panic at runtime in the panicwrap -// method. Treat it like nil instead. -// -// This is so people can implement driver.Value on value types and -// still use nil pointers to those types to mean nil/NULL, just like -// string/*string. -// -// This is an exact copy of the same-named unexported function from the -// database/sql package. -func callValuerValue(vr driver.Valuer) (v driver.Value, err error) { - if rv := reflect.ValueOf(vr); rv.Kind() == reflect.Ptr && - rv.IsNil() && - rv.Type().Elem().Implements(valuerReflectType) { - return nil, nil - } - return vr.Value() -} diff --git a/src/connector/go/src/taosSql/taosLog.go b/src/connector/go/src/taosSql/taosLog.go deleted file mode 100755 index 63af5e34c15720403c4e09730e3bada54722fc39..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/taosLog.go +++ /dev/null @@ -1,120 +0,0 @@ -/* - * 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 . - */ - -package taosSql - -import ( - "bufio" - "errors" - "fmt" - "io" - "log" - "os" - "strings" -) - -// Various errors the driver might return. -var ( - errInvalidConn = errors.New("invalid connection") - errConnNoExist = errors.New("no existent connection ") -) - -var taosLog *log.Logger - -// SetLogger is used to set the logger for critical errors. -// The initial logger -func taosLogInit() { - cfgName := "/etc/taos/taos.cfg" - logNameDefault := "/var/log/taos/taosgo.log" - var logName string - - // get log path from cfg file - cfgFile, err := os.OpenFile(cfgName, os.O_RDONLY, 0644) - defer cfgFile.Close() - if err != nil { - fmt.Println(err) - logName = logNameDefault - } else { - logName, err = getLogNameFromCfg(cfgFile) - if err != nil { - fmt.Println(err) - logName = logNameDefault - } - } - - logFile, err := os.OpenFile(logName, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - fmt.Println(err) - os.Exit(1) - } - taosLog = log.New(logFile, "", log.LstdFlags) - taosLog.SetPrefix("TAOS DRIVER ") - taosLog.SetFlags(log.LstdFlags|log.Lshortfile) -} - -func getLogNameFromCfg(f *os.File) (string, error) { - // Create file buf, *Reader - r := bufio.NewReader(f) - for { - //read one line, return to slice b - b, _, err := r.ReadLine() - if err != nil { - if err == io.EOF { - break - } - panic(err) - } - - // Remove space of left and right - s := strings.TrimSpace(string(b)) - if strings.Index(s, "#") == 0 { - // comment line - continue - } - - if len(s) == 0 { - continue - } - - var ns string - // If there is a comment on the right of the line, must be remove - index := strings.Index(s, "#") - if index > 0 { - // Gets the string to the left of the comment to determine whether it is empty - ns = s[:index] - if len(ns) == 0 { - continue - } - } else { - ns = s; - } - - ss := strings.Fields(ns) - if strings.Compare("logDir", ss[0]) != 0 { - continue - } - - if len(ss) < 2 { - break - } - - // Add a filename after the path - logName := ss[1] + "/taosgo.log" - return logName,nil - } - - return "", errors.New("no config log path, use default") -} - diff --git a/src/connector/go/src/taosSql/taosSqlCgo.go b/src/connector/go/src/taosSql/taosSqlCgo.go deleted file mode 100755 index cc3aaa1658813cdfe667c5402c029525860fbf01..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/taosSqlCgo.go +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 . - */ -package taosSql - -/* -#cgo CFLAGS : -I/usr/include -#cgo LDFLAGS: -L/usr/lib -ltaos -#include -#include -#include -#include -*/ -import "C" - -import ( - "errors" - "unsafe" -) - -func (mc *taosConn) taosConnect(ip, user, pass, db string, port int) (taos unsafe.Pointer, err error) { - cuser := C.CString(user) - cpass := C.CString(pass) - cip := C.CString(ip) - cdb := C.CString(db) - defer C.free(unsafe.Pointer(cip)) - defer C.free(unsafe.Pointer(cuser)) - defer C.free(unsafe.Pointer(cpass)) - defer C.free(unsafe.Pointer(cdb)) - - taosObj := C.taos_connect(cip, cuser, cpass, cdb, (C.ushort)(port)) - if taosObj == nil { - return nil, errors.New("taos_connect() fail!") - } - - return (unsafe.Pointer)(taosObj), nil -} - -func (mc *taosConn) taosQuery(sqlstr string) (int, error) { - //taosLog.Printf("taosQuery() input sql:%s\n", sqlstr) - - csqlstr := C.CString(sqlstr) - defer C.free(unsafe.Pointer(csqlstr)) - code := int(C.taos_query(mc.taos, csqlstr)) - - if 0 != code { - mc.taos_error() - errStr := C.GoString(C.taos_errstr(mc.taos)) - taosLog.Println("taos_query() failed:", errStr) - taosLog.Printf("taosQuery() input sql:%s\n", sqlstr) - return 0, errors.New(errStr) - } - - // read result and save into mc struct - num_fields := int(C.taos_field_count(mc.taos)) - if 0 == num_fields { // there are no select and show kinds of commands - mc.affectedRows = int(C.taos_affected_rows(mc.taos)) - mc.insertId = 0 - } - - return num_fields, nil -} - -func (mc *taosConn) taos_close() { - C.taos_close(mc.taos) -} - -func (mc *taosConn) taos_error() { - // free local resouce: allocated memory/metric-meta refcnt - //var pRes unsafe.Pointer - pRes := C.taos_use_result(mc.taos) - C.taos_free_result(pRes) -} diff --git a/src/connector/go/src/taosSql/utils.go b/src/connector/go/src/taosSql/utils.go deleted file mode 100755 index a104322fcc9012ea0370bdbea9b89e6674daabf3..0000000000000000000000000000000000000000 --- a/src/connector/go/src/taosSql/utils.go +++ /dev/null @@ -1,422 +0,0 @@ -/* - * 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 . - */ -package taosSql - -/* -#cgo CFLAGS : -I/usr/include -#include -#cgo LDFLAGS: -L/usr/lib -ltaos -void taosSetAllocMode(int mode, const char* path, _Bool autoDump); -void taosDumpMemoryLeak(); -*/ -import "C" - - -import ( - "database/sql/driver" - "errors" - "fmt" - "sync/atomic" - "time" - "unsafe" -) - -// Returns the bool value of the input. -// The 2nd return value indicates if the input was a valid bool value -func readBool(input string) (value bool, valid bool) { - switch input { - case "1", "true", "TRUE", "True": - return true, true - case "0", "false", "FALSE", "False": - return false, true - } - - // Not a valid bool value - return -} - -/****************************************************************************** -* Time related utils * -******************************************************************************/ - -// NullTime represents a time.Time that may be NULL. -// NullTime implements the Scanner interface so -// it can be used as a scan destination: -// -// var nt NullTime -// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt) -// ... -// if nt.Valid { -// // use nt.Time -// } else { -// // NULL value -// } -// -// This NullTime implementation is not driver-specific -type NullTime struct { - Time time.Time - Valid bool // Valid is true if Time is not NULL -} - -// Scan implements the Scanner interface. -// The value type must be time.Time or string / []byte (formatted time-string), -// otherwise Scan fails. -func (nt *NullTime) Scan(value interface{}) (err error) { - if value == nil { - nt.Time, nt.Valid = time.Time{}, false - return - } - - switch v := value.(type) { - case time.Time: - nt.Time, nt.Valid = v, true - return - case []byte: - nt.Time, err = parseDateTime(string(v), time.UTC) - nt.Valid = (err == nil) - return - case string: - nt.Time, err = parseDateTime(v, time.UTC) - nt.Valid = (err == nil) - return - } - - nt.Valid = false - return fmt.Errorf("Can't convert %T to time.Time", value) -} - -// Value implements the driver Valuer interface. -func (nt NullTime) Value() (driver.Value, error) { - if !nt.Valid { - return nil, nil - } - return nt.Time, nil -} - -func parseDateTime(str string, loc *time.Location) (t time.Time, err error) { - base := "0000-00-00 00:00:00.0000000" - switch len(str) { - case 10, 19, 21, 22, 23, 24, 25, 26: // up to "YYYY-MM-DD HH:MM:SS.MMMMMM" - if str == base[:len(str)] { - return - } - t, err = time.Parse(timeFormat[:len(str)], str) - default: - err = fmt.Errorf("invalid time string: %s", str) - return - } - - // Adjust location - if err == nil && loc != time.UTC { - y, mo, d := t.Date() - h, mi, s := t.Clock() - t, err = time.Date(y, mo, d, h, mi, s, t.Nanosecond(), loc), nil - } - - return -} - -// zeroDateTime is used in formatBinaryDateTime to avoid an allocation -// if the DATE or DATETIME has the zero value. -// It must never be changed. -// The current behavior depends on database/sql copying the result. -var zeroDateTime = []byte("0000-00-00 00:00:00.000000") - -const digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" -const digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" - -/****************************************************************************** -* Convert from and to bytes * -******************************************************************************/ - -func uint64ToBytes(n uint64) []byte { - return []byte{ - byte(n), - byte(n >> 8), - byte(n >> 16), - byte(n >> 24), - byte(n >> 32), - byte(n >> 40), - byte(n >> 48), - byte(n >> 56), - } -} - -func uint64ToString(n uint64) []byte { - var a [20]byte - i := 20 - - // U+0030 = 0 - // ... - // U+0039 = 9 - - var q uint64 - for n >= 10 { - i-- - q = n / 10 - a[i] = uint8(n-q*10) + 0x30 - n = q - } - - i-- - a[i] = uint8(n) + 0x30 - - return a[i:] -} - -// treats string value as unsigned integer representation -func stringToInt(b []byte) int { - val := 0 - for i := range b { - val *= 10 - val += int(b[i] - 0x30) - } - return val -} - -// reserveBuffer checks cap(buf) and expand buffer to len(buf) + appendSize. -// If cap(buf) is not enough, reallocate new buffer. -func reserveBuffer(buf []byte, appendSize int) []byte { - newSize := len(buf) + appendSize - if cap(buf) < newSize { - // Grow buffer exponentially - newBuf := make([]byte, len(buf)*2+appendSize) - copy(newBuf, buf) - buf = newBuf - } - return buf[:newSize] -} - -// escapeBytesBackslash escapes []byte with backslashes (\) -// This escapes the contents of a string (provided as []byte) by adding backslashes before special -// characters, and turning others into specific escape sequences, such as -// turning newlines into \n and null bytes into \0. -func escapeBytesBackslash(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - for _, c := range v { - switch c { - case '\x00': - buf[pos] = '\\' - buf[pos+1] = '0' - pos += 2 - case '\n': - buf[pos] = '\\' - buf[pos+1] = 'n' - pos += 2 - case '\r': - buf[pos] = '\\' - buf[pos+1] = 'r' - pos += 2 - case '\x1a': - buf[pos] = '\\' - buf[pos+1] = 'Z' - pos += 2 - case '\'': - buf[pos] = '\\' - buf[pos+1] = '\'' - pos += 2 - case '"': - buf[pos] = '\\' - buf[pos+1] = '"' - pos += 2 - case '\\': - buf[pos] = '\\' - buf[pos+1] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - return buf[:pos] -} - -// escapeStringBackslash is similar to escapeBytesBackslash but for string. -func escapeStringBackslash(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - switch c { - case '\x00': - buf[pos] = '\\' - buf[pos+1] = '0' - pos += 2 - case '\n': - buf[pos] = '\\' - buf[pos+1] = 'n' - pos += 2 - case '\r': - buf[pos] = '\\' - buf[pos+1] = 'r' - pos += 2 - case '\x1a': - buf[pos] = '\\' - buf[pos+1] = 'Z' - pos += 2 - //case '\'': - // buf[pos] = '\\' - // buf[pos+1] = '\'' - // pos += 2 - case '"': - buf[pos] = '\\' - buf[pos+1] = '"' - pos += 2 - case '\\': - buf[pos] = '\\' - buf[pos+1] = '\\' - pos += 2 - default: - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeBytesQuotes escapes apostrophes in []byte by doubling them up. -// This escapes the contents of a string by doubling up any apostrophes that -// it contains. This is used when the NO_BACKSLASH_ESCAPES SQL_MODE is in -// effect on the server. -func escapeBytesQuotes(buf, v []byte) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for _, c := range v { - if c == '\'' { - buf[pos] = '\'' - buf[pos+1] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -// escapeStringQuotes is similar to escapeBytesQuotes but for string. -func escapeStringQuotes(buf []byte, v string) []byte { - pos := len(buf) - buf = reserveBuffer(buf, len(v)*2) - - for i := 0; i < len(v); i++ { - c := v[i] - if c == '\'' { - buf[pos] = '\'' - buf[pos+1] = '\'' - pos += 2 - } else { - buf[pos] = c - pos++ - } - } - - return buf[:pos] -} - -/****************************************************************************** -* Sync utils * -******************************************************************************/ - -// noCopy may be embedded into structs which must not be copied -// after the first use. -// -// See https://github.com/golang/go/issues/8005#issuecomment-190753527 -// for details. -type noCopy struct{} - -// Lock is a no-op used by -copylocks checker from `go vet`. -func (*noCopy) Lock() {} - -// atomicBool is a wrapper around uint32 for usage as a boolean value with -// atomic access. -type atomicBool struct { - _noCopy noCopy - value uint32 -} - -// IsSet returns whether the current boolean value is true -func (ab *atomicBool) IsSet() bool { - return atomic.LoadUint32(&ab.value) > 0 -} - -// Set sets the value of the bool regardless of the previous value -func (ab *atomicBool) Set(value bool) { - if value { - atomic.StoreUint32(&ab.value, 1) - } else { - atomic.StoreUint32(&ab.value, 0) - } -} - -// TrySet sets the value of the bool and returns whether the value changed -func (ab *atomicBool) TrySet(value bool) bool { - if value { - return atomic.SwapUint32(&ab.value, 1) == 0 - } - return atomic.SwapUint32(&ab.value, 0) > 0 -} - -// atomicError is a wrapper for atomically accessed error values -type atomicError struct { - _noCopy noCopy - value atomic.Value -} - -// Set sets the error value regardless of the previous value. -// The value must not be nil -func (ae *atomicError) Set(value error) { - ae.value.Store(value) -} - -// Value returns the current error value -func (ae *atomicError) Value() error { - if v := ae.value.Load(); v != nil { - // this will panic if the value doesn't implement the error interface - return v.(error) - } - return nil -} - -func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { - dargs := make([]driver.Value, len(named)) - for n, param := range named { - if len(param.Name) > 0 { - // TODO: support the use of Named Parameters #561 - return nil, errors.New("taosSql: driver does not support the use of Named Parameters") - } - dargs[n] = param.Value - } - return dargs, nil -} - - -/****************************************************************************** -* Utils for C memory issues debugging * -******************************************************************************/ -func SetAllocMode(mode int32, path string) { - cpath := C.CString(path) - defer C.free(unsafe.Pointer(cpath)) - C.taosSetAllocMode(C.int(mode), cpath, false) -} - -func DumpMemoryLeak() { - C.taosDumpMemoryLeak() -}