Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
d30ab1c5
T
TDengine
项目概览
taosdata
/
TDengine
大约 1 年 前同步成功
通知
1184
Star
22015
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
d30ab1c5
编写于
4月 13, 2020
作者:
S
slguan
提交者:
GitHub
4月 13, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1600 from taosdata/change-go-driver-to-gitsubmodule-for-2.0
change go driver to git submodule.
上级
9d44cb10
b9c4fc22
变更
13
隐藏空白更改
内联
并排
Showing
13 changed file
with
4 addition
and
1993 deletion
+4
-1993
.gitmodules
.gitmodules
+3
-0
src/connector/go
src/connector/go
+1
-0
src/connector/go/src/taosSql/connection.go
src/connector/go/src/taosSql/connection.go
+0
-368
src/connector/go/src/taosSql/connector.go
src/connector/go/src/taosSql/connector.go
+0
-49
src/connector/go/src/taosSql/const.go
src/connector/go/src/taosSql/const.go
+0
-51
src/connector/go/src/taosSql/driver.go
src/connector/go/src/taosSql/driver.go
+0
-43
src/connector/go/src/taosSql/dsn.go
src/connector/go/src/taosSql/dsn.go
+0
-202
src/connector/go/src/taosSql/result.go
src/connector/go/src/taosSql/result.go
+0
-200
src/connector/go/src/taosSql/rows.go
src/connector/go/src/taosSql/rows.go
+0
-296
src/connector/go/src/taosSql/statement.go
src/connector/go/src/taosSql/statement.go
+0
-158
src/connector/go/src/taosSql/taosLog.go
src/connector/go/src/taosSql/taosLog.go
+0
-120
src/connector/go/src/taosSql/taosSqlCgo.go
src/connector/go/src/taosSql/taosSqlCgo.go
+0
-84
src/connector/go/src/taosSql/utils.go
src/connector/go/src/taosSql/utils.go
+0
-422
未找到文件。
.gitmodules
0 → 100644
浏览文件 @
d30ab1c5
[submodule "src/connector/go"]
path = src/connector/go
url = https://github.com/taosdata/driver-go
go
@
8c58c512
Subproject commit 8c58c512b6acda8bcdfa48fdc7140227b5221766
src/connector/go/src/taosSql/connection.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
}
src/connector/go/src/taosSql/connector.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
{}
}
src/connector/go/src/taosSql/const.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
)
src/connector/go/src/taosSql/driver.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
()
}
src/connector/go/src/taosSql/dsn.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
}
src/connector/go/src/taosSql/result.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package
taosSql
/*
#cgo CFLAGS : -I/usr/include
#cgo LDFLAGS: -L/usr/lib -ltaos
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <taos.h>
*/
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
)))
}
src/connector/go/src/taosSql/rows.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package
taosSql
/*
#cgo CFLAGS : -I/usr/include
#cgo LDFLAGS: -L/usr/lib -ltaos
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <taos.h>
*/
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
}
}
src/connector/go/src/taosSql/statement.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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
()
}
src/connector/go/src/taosSql/taosLog.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
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"
)
}
src/connector/go/src/taosSql/taosSqlCgo.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package
taosSql
/*
#cgo CFLAGS : -I/usr/include
#cgo LDFLAGS: -L/usr/lib -ltaos
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <taos.h>
*/
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
)
}
src/connector/go/src/taosSql/utils.go
已删除
100755 → 0
浏览文件 @
9d44cb10
/*
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
*
* 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 <http://www.gnu.org/licenses/>.
*/
package
taosSql
/*
#cgo CFLAGS : -I/usr/include
#include <stdlib.h>
#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
()
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录