SAP (formerly sybase) ASE/RS/IQ driver written in pure go



import ""

Package tds is a pure Go Sybase ASE/IQ/RS driver for the database/sql package.


This is a beta release. This driver has yet to be battle tested on production workload. Version 1.0 will be released when this driver will be production ready


- Sybase ASE 12.5 or higher
- go 1.8 or higher.


Package installation is done via go-get:

$ go get -u


It implements most of the database/sql functionalities. To connect to a sybase instance, import the package and use the regular database/sql APIs:

import (

	_ ""

func main() {
	cnxStr := "tds://my_user:[email protected]:5000/pubs?charset=utf8"
	db, err := sql.Open("tds", cnxStr)
	if err != nil {

	id := 2
	rows, err := db.Query("select * from authors where id = ?", id)

Connection String

The connection string is pretty standard and uses the URL format:


Connection parameters

The most common ones are:

- username - the database server login. Mandatory.
- password - The login's password. Mandatory.
- host - The host to connect to. Mandatory.
- port - The port to bind to. Mandatory.
- database - The database to use. You will connect to the login's
  default database if not specified.
- charset - The client's character set. Default to utf8.
  Please refer to the character sets section.
- readTimeout - read timeout in seconds.
- writeTimeout - write timeout in seconds.
- textSize - max size of textsize fields in bytes.
  It is suggested to raise it to avoid truncation.

Less frequently used ones:

- ssl - Whether or not to use SSL. The default is not to use ssl.
  Set to "on" if the server is setup to use ssl.
- encryptPassword - Can be "yes" to require password encryption,
  "no" to disable it, and "try" to try encrytping password an falling back
  to plain text password. Password encryption works on Sybase ASE 15.5
  or higher and uses RSA.
- packetSize - Network packet size. Must be less than or equal the server's
  max network packet size. The default is the server's default network
  packet size.
- applicationName - the name of your application.
  It is a best practice to set it.

Query parameters

Most of the database/sql APIs are implemented, with a major one missing: named parameters. Please use the question mark '?' as a placeholder for parameters :

res, err = tx.Exec("insert into author (id, name) values (?, ?)", 2, "Paul")

Supported data types

Almost all of the sybase ASE datatypes are supported, with the exception of lob locators. The type mapping between the server and the go data types is as follows:

- varchar/text/char/unichar/univarchar/xml => string
- int/smalling/bigint => int64.
  Unsigned bigints with a value > Math.MaxInt64 will be returned as uint64
- date/datetime/bigdate/bigdatetime => time.Time
- image/binary/varbinary/image => []byte
- real/float => float64
- decimal/numeric/money/smallmoney => tds.Num.
  Please see the  "precise numerical types" section.

Precise numerical types

decimal/numeric/money/smallmoney data can be given as parameters using any of the go numerical types. However one should never use float64 if a loss of precision is not tolerated. To implement precise floating point numbers, this driver provides a "Num" datatype, which is a wrapper around big.Rat.

It implements the value.Scanner interface, you can thus instanciate it this way:

num := tds.Num{precision: 16, scale: 2}

To access the underlying big.Rat:

rat := num.Rat()

Num also implements the stringer interface to pretty print its value. Please refer to the tds.Num godoc for more information.

Character set encoding

This driver assumes by default that the client uses utf8 strings and will ask the server to convert back and forth to/from this charset.

If utf8 charset conversion is not supported on the server, and if the charset conversion is not supported by, you can add client-side character set conversion with the following code:

var e encoding.Encoding
tds.RegisterEncoding("name", e)

You will have to handle it yourself and use a charset supported by the server.

Custom error handling

One can set a custom error callback to process server errors before the regular error processing routing. This allows handling showplan messages and print statement.

The following demonstrates how to handle showplan and print messages:

conn := sql.Open("tds", url)

// print showplan messages and all
conn.Driver().(tds.ErrorHandler).SetErrorhandler(func(m tds.SybError) bool {
	if m.Severity == 10 {
		if (m.MsgNumber >= 3612 && m.MsgNumber <= 3615) ||
			(m.MsgNumber >= 6201 && m.MsgNumber <= 6299) ||
			(m.MsgNumber >= 10201 && m.MsgNumber <= 10299) {
		} else {
			fmt.Println(strings.TrimRight(m.Message, "\n"))

	if m.Severity > 10 {
	return m.Severity > 10


As of now the driver does not support bulk insert and named parameters. Password encryption only works for Sybase ASE > 15.5.


You can use stmt_test.go and session_test.go for sample usage, as follows:

export TDS_USERNAME=test_user
export TDS_PASSWORD=test_password
export TDS_SERVER=localhost:5000
go test


This driver is released under the go license


- the freetds and jtds protocol documentation.
- Microsoft for releasing the full tds specification.
  There are differences, however a lot of it is relevant.
- for most of the tests.
- The Sybase::TdsServer perl module for capabilities handling.
  • Does this work with sybase 16 ?

    Does this work with sybase 16 ?


    I was doing a quick check of this driver against our sybase ase 16. I encountered a hang on db.Ping then timedout. Before i dig deeper, was wondering if this works against 16?



    ASE 16 SP03 password encryption 
    opened by jaijiv 17
  • I can not use @ in password - Please help

    I can not use @ in password - Please help

    While I am using a special character @ in the password it is not working after the first @ character it considers the host name. like

    db, err = sql.Open("tds", "tds://username:pass#word@abcde#[email protected]:1234?charset=utf8")

    it is considering "abcde#[email protected]" rather then

    Please help!

    opened by sanjayverma09 16
  • So Exciting!

    So Exciting!

    Greetings, I discovered this library from the Golang Weekly email newsletter. I am SO excited to see more drivers supporting Sybase (SAP) databases. I do a lot of work on ASE, and have fallen in love with go the last couple years, but it has always been tough to use go with Sybase products.

    I've been using the gofreetds package by minus5, but it's major limitation for my team is that it that particular implementation requires the linux freetds installed on the system, whereas almost my whole team are Windows users.

    I have a fork of that repo here with a couple small tweaks that let Sybase be used as the database/sql package.

    Anyways, please let me know how I could help in making this package production ready!

    opened by andyedison 12
  • cannot connect to Sybase ASE 15.0.3

    cannot connect to Sybase ASE 15.0.3

    This project looks very promising. Thanks for working on it and sharing.

    I'm trying to use this project to connect to a Sybase ASE 15.0.3 database. I have build the connection string as per the instructions. The sql.Open() command works with no error, but when I try db.Ping() or db.Query() I get an exception. I'm new to Go and am having a hard time finding helpful information from the error message. I am using the latest from master. Do you have any pointers? The error is below. Thanks,

    panic: runtime error: index out of range

    goroutine 1 [running]:*session).login(0xc00055c340, 0xc00040c756, 0x23, 0xc00040c746, 0x6, 0xc00040c74d, 0x8, 0x0, 0x0, 0x0, ...) /Users/user/Development/Go/src/ +0x1bd6, 0x23, 0xc00040c746, 0x6, 0xc00040c74d, 0x8, 0x0, 0x0, 0x0, 0x0, ...) /Users/user/Development/Go/src/ +0x5fa, 0x3d, 0x15477d8, 0xc0004a11c8, 0x10421e4) /Users/user/Development/Go/src/ +0x124*sybDriver).Open(0x1ebb1e0, 0xc00040c740, 0x3d, 0xc0004a11d8, 0x10352c3, 0x10c6ddd, 0xc0004a11e8) /Users/user/Development/Go/src/ +0x39

    opened by javabilities 6
  • Infinite loop when connection unexpectedly dies

    Infinite loop when connection unexpectedly dies

    When the connection is interrupted unexpectedly (eg, stateful firewall loses track of the connection) it seems that when database/sql tries to signal to the driver to close the connection it gets stuck in a busy loop causing 100% CPU usage.

    Stack trace of the offending goroutine running under go version go1.12.9 linux/amd64:

    goroutine 855659 [runnable]:
    syscall.Syscall(0x0, 0x7, 0xc0001565a8, 0x1, 0x0, 0x1, 0x0)
            /usr/local/go/src/syscall/asm_linux_amd64.s:18 +0x5, 0xc0001565a8, 0x1, 0x8, 0x0, 0x0, 0x0)
            /usr/local/go/src/syscall/zsyscall_linux_amd64.go:732 +0x5a
    internal/poll.(*FD).Read(0xc00014eb00, 0xc0001565a8, 0x1, 0x8, 0x0, 0x0, 0x0)
            /usr/local/go/src/internal/poll/fd_unix.go:165 +0x131
    net.(*netFD).Read(0xc00014eb00, 0xc0001565a8, 0x1, 0x8, 0x0, 0xe97160, 0xc000096050)
            /usr/local/go/src/net/fd_unix.go:202 +0x4f
    net.(*conn).Read(0xc0000ac2b8, 0xc0001565a8, 0x1, 0x8, 0x0, 0x0, 0x0)
            /usr/local/go/src/net/net.go:177 +0x69
    io.ReadAtLeast(0x7f47d8c79a08, 0xc0004741c0, 0xc0001565a8, 0x1, 0x8, 0x1, 0x0, 0xe97160, 0xc000096050)
            /usr/local/go/src/io/io.go:310 +0x88
            /usr/local/go/src/io/io.go:329*Encoder).Read(0xc000156588, 0xc0001565a8, 0x1, 0x8, 0x0, 0xe97160, 0xc000096050)
            /home/jenkins_slave/workspace/tds-test/src/ +0x6b*Encoder).ReadByte(...)
            /home/jenkins_slave/workspace/tds-test/src/*header).read(0xc000156490, 0xc000156588, 0xe97160, 0xc000096050)
            /home/jenkins_slave/workspace/tds-test/src/ +0x1ab*buf).readPkt(0xc000156480, 0xc000499001, 0xe97160, 0xc000096050)
            /home/jenkins_slave/workspace/tds-test/src/ +0x54*buf).processCancel(0xc000156480, 0x0, 0x0)
            /home/jenkins_slave/workspace/tds-test/src/ +0xcf*buf).sendPkt(0xc000156480, 0xeb3401, 0xc0003c8350, 0x0)
            /home/jenkins_slave/workspace/tds-test/src/ +0x1c0*buf).send(0xc000156480, 0xeadfe0, 0xc0002fb620, 0xc0003c830f, 0xc000499180, 0x1, 0x1, 0x0, 0x0)
            /home/jenkins_slave/workspace/tds-test/src/ +0xee*session).Close(0xc0003ff040, 0x0, 0x0)
            /home/jenkins_slave/workspace/tds-test/src/ +0x192
            /usr/local/go/src/database/sql/sql.go:521 +0x49
    database/sql.withLock(0xea1e80, 0xc000119280, 0xc000499270)
            /usr/local/go/src/database/sql/sql.go:3097 +0x63
    database/sql.(*driverConn).finalClose(0xc000119280, 0x0, 0x4)
            /usr/local/go/src/database/sql/sql.go:519 +0x130
    database/sql.(*driverConn).Close(0xc000119280, 0xc000097390, 0xc000097390)
            /usr/local/go/src/database/sql/sql.go:500 +0x138
    database/sql.(*DB).putConn(0xc00010e180, 0xc000119280, 0xe97160, 0xc000097390, 0xc000119201)
            /usr/local/go/src/database/sql/sql.go:1250 +0x2d5
    database/sql.(*DB).pingDC(0xc00010e180, 0xeae020, 0xc000520e40, 0xc000119280, 0xc0004994a8, 0x0, 0x0)
            /usr/local/go/src/database/sql/sql.go:719 +0x84
    database/sql.(*DB).PingContext(0xc00010e180, 0xeae020, 0xc000520e40, 0xc000499520, 0xd567e0)
            /usr/local/go/src/database/sql/sql.go:742 +0x170

    In this instance, db.PingContext() was called which made the database/sql package realise there was a bad connection in the pool. Relevant bit of code in the database/sql package that kicks off the chain of events:

    Subsequent calls to db.PingContext() worked fine using a fresh connection while the offending go routine was still caught up in a busy loop.

    opened by nvx 5
  • Fix return error value when login fails

    Fix return error value when login fails

    At login failure the returned error is always nil and this creates a connection at sql.Open that is in an invalid state instead of reporting the sybase error that happened during the connection.

    After the fix it returns the correct error value and the sql.Open call properly reports the error message

    opened by grethy 5
  • Can't specify a dbname

    Can't specify a dbname

    Hello everyone, First of all thank's for your work ! This is my issue:

    package main
    import (
    	_ "flag"
    	_ ""
    func main() {
    	db, err := sql.Open("tds", "tds://username:password@IP:2638/dbnameA?charset=utf8")
    	if err != nil {
    		fmt.Printf("Failed to open database: %v", err)
    	defer db.Close()
    	err = db.Ping()
    	if err != nil {
    		fmt.Printf("Failed to ping database: %v", err)
    	var result string
    	row, _ := db.Query("select db_name()")
    	for row.Next() {

    Response : ok defaultDB

    If I specify a db name into the connection string I can do "select x from TableOfDbA" but if I do "select db_name()" the response will be DefaultDB. If I specify a Db into the connection string, and if this DB doesn't exist, I don't have an error message because a connection is made with the default db. This is a problem because I use this script to monitor all db on the server. Thank's for your help

    opened by yohan212 4
  • cannot connect to Sybase ASE 12.5.4 with charset=cp850

    cannot connect to Sybase ASE 12.5.4 with charset=cp850

    I'm trying to use this project to connect to a Sybase ASE 12.5.4 database. cnxStr := "tds://sa:@" But it didn't work,the error is blow. Do you have any pointers? Thanks tds: cannot encode to 'cp850' charset

    opened by slam-coder 4
  • add custom encoding registration function

    add custom encoding registration function

    I'm new to golang.

    This is experimental.

    I hope somebody that advise if there is better way.

    Fixes #6

    Usage Sample:

    package foo
    import (
    var ShiftJIS encoding.Encoding = &sjisEncoding{}
    type sjisEncoding struct {
    func (e *sjisEncoding) NewDecoder() *encoding.Decoder {
    	return japanese.ShiftJIS.NewDecoder()
    func (e *sjisEncoding) NewEncoder() *encoding.Encoder {
    	return &encoding.Encoder{Transformer: &shiftJISEncoder{}}
    type shiftJISEncoder struct{ transform.NopResetter }
    // Transform using mahonia.
    func (shiftJISEncoder) Transform(dst, src []byte, atEOF bool) (nDst, nSrc int, err error) {
    	encoder := mahonia.NewEncoder("sjis")
    	encoded := []byte(encoder.ConvertString(string(src)))
    	copy(dst, encoded)
    	return nDst + len(encoded), nSrc + len(src), err
    // override `sjis` encoding
    tds.RegisterEncoding("sjis", foo.ShiftJIS)
    opened by wiro34 4
  • Incorrectly implemented Close() operation

    Incorrectly implemented Close() operation

    Func Close() sends logout packet, then immediately close the socket, without waiting to server's response. It causes:

    • At server: logged error messge A client process exited abnormally, or a network error was encountered.
    • At network level: multiple TCP RST packets are sent back to the server, when logout response arrives
    opened by hpfousac 3
  • Export Driver

    Export Driver

    Most SQL driver packages either export the driver struct directly, or export an instance of the driver struct. Note that database/sql package does not provide a way to obtain a driver.Driver for a given driver name outside of the sql package itself.

    This is useful as it allows packages like instrumentedsql to wrap a driver to add instrumentation. For example leverages the exported sqlite3.SQLiteDriver struct to create a new driver instance to wrap. This same pattern is used by the postgres driver pq where the struct is pq.Driver, go-mssqldb where the struct is mssqldb.Driver, and mysql as mysql.MySQLDriver. Oddly the go-oci8 library takes the approach of exporting an instance of the driver at oci8.Driver rather than the struct, but this still works fine as long as a sql driver.Driver can be obtained.

    I'm not sure which of the two options is the most idiomatic, but more do seem to opt for exporting the struct itself rather than exporting an instance of the driver.

    opened by nvx 3
  • Insert failing for columns having zero value

    Insert failing for columns having zero value

    Code used to insert row(values are having numeric data type in database): db.Exec("INSERT INTO table_name (col_a, col_b) VALUES (?, ?)", 1.23, 0)

    Error Received: tds: error while scanning array of bytes to numeric: tds: could not parse string . to number

    Debugged further and found that num.String() in line below is returning value = .

    On further debugging into num.String() function, we found that the following IsInt() check is getting failed:

    opened by archit4077sh 1
  • How to check if tds.Num represents a NULL value

    How to check if tds.Num represents a NULL value

    After scanning successfully a NULL value into tds.Num, what is the public method to determine if is NULL or not? tds.Num has only String() and Rat() methods?

    tds.Num{r:big.Rat{a:big.Int{neg:false, abs:big.nat(nil)}, b:big.Int{neg:false, abs:big.nat(nil)}}, precision:0, scale:0, isNull:true}

    opened by hqin 2
  • Failure handling some

    Failure handling some "real" columns on Sybase 11

    I'm not sure what's happening and I'm not sure how to debug this. I'm open to suggestions on how to gather the right data.

    I'm connecting to Sybase and thda/tds seems to handle the TDS protocol this server version is using just fine normally. However I have one particular query that causes it to behave oddly, sometimes returning no data and sometimes entering an infinite loop or crashing.

    I've simplified the failing query to select convert(real, @@timeticks) x. It does not fail if I do convert(real, 1) or just do select @@timeticks. It does fail with converting other @@ variables to real though. It also doesn't fail if I do convert(float(5), @@timeticks) but does fail if I do convert(float(4) @@timeticks)

    I noted "real" is handled as a single precision float, I wonder if the TDS protocol isn't actually sending a double-width float though? Or perhaps the single precision parsing is just not quite right?

    opened by gsstark 2
  • DB Connection Stuck during Login

    DB Connection Stuck during Login

    We have an application that occasionally stuck and the stack trace shows that it goes into this branch and eventually at stuck at a network read in go runtime code.

    May I know the intention of this readPkt call after EOF encountered?

    We don't have any timeout params set as part of the conn string, so from the code, it looks like it is going to take defaultLoginTimeout = 20, which is in seconds. but it doesn't look like this timeout is kicking in for us either. The process is stuck for at least 2 hours - very likely at the exact same place.

    From our investigation, we can see from the host netstat output that the connection is in ESTABLISHED state and from the Sybase Text Report that the DB server agrees with that.

    I will try to post the stack trace, but it is a bit challenging to get it out from firm network. It is essentially coming from newSession(...) in session.go, then login(...), then initState(...)

    opened by shou1dwe 4
  • tds.Num into type *sql.RawBytes

    tds.Num into type *sql.RawBytes

    I am querying a table I don't know the schema of. So I am using this to gather the table contents:

    cols, err := rows.Columns() // Remember to check err afterwards
    vals := make([]interface{}, len(cols))
    for i, _ := range cols {
    	vals[i] = new(sql.RawBytes)
    for rows.Next() {
    	if err := rows.Scan(vals...); err != nil {
            // Check for a scan error.
    	// Query rows will be closed with defer.

    However when I get to a column with type money I get the following error:

    unsupported Scan, storing driver.Value type tds.Num into type *sql.RawBytes

    opened by ashf 1
  • v0.1.7(Oct 1, 2019)

  • v0.1.6(Jun 12, 2019)

    • Fixes faulty error handling when looping over the responses.
    • Add a way to specify a custom char encoder (#7) as some go character sets have a undesired behavior.
    Source code(tar.gz)
    Source code(zip)
  • v0.1.5(Feb 26, 2019)

  • v0.1.4(Feb 3, 2019)

    Alas password encryption does not work for SAP ASE < 15.5 or SAP RS < 15.7. This release handles more gracefully 15.0.X server which failed without the encryptPassword=No parameter.

    Source code(tar.gz)
    Source code(zip)
  • v0.1.3(Jan 28, 2019)

    This release attempts to make the library more fail proof.

    • avoid returning nil pointers to the caller in all visible API
    • create empty structs linked with invalid session to use as return values on error
    • do not mark the connection invalid when receiving tds error messages. Only protocol/packet/struct parsing errors will mark the session as invalid
    • fix connection leaks in tests
    Source code(tar.gz)
    Source code(zip)
  • v0.1.2(Jan 21, 2019)

    • Fix prepared statement support for ASE < 15.7.
    • Swith to plain text passwords when encryptPassword is set to "try", but replication servers generate unvalid RSA keys.
    Source code(tar.gz)
    Source code(zip)
I work with databases.
Qmgo - The Go driver for MongoDB. It‘s based on official mongo-go-driver but easier to use like Mgo.

Qmgo English | 简体中文 Qmgo is a Go driver for MongoDB . It is based on MongoDB official driver, but easier to use like mgo (such as the chain call). Qmg

Qiniu Cloud 1k Dec 28, 2022
Go driver for PostgreSQL over SSH. This driver can connect to postgres on a server via SSH using the local ssh-agent, password, or private-key.

pqssh Go driver for PostgreSQL over SSH. This driver can connect to postgres on a server via SSH using the local ssh-agent, password, or private-key.

mattn 52 Nov 6, 2022
Pure Go Postgres driver for database/sql

pq - A pure Go postgres driver for Go's database/sql package Install go get Features SSL Handles bad connections for database/sql S

null 7.8k Jan 2, 2023
Microsoft SQL server driver written in go language

A pure Go MSSQL driver for Go's database/sql package Install Requires Go 1.8 or above. Install with go get . Connecti

null 1.7k Dec 26, 2022
Mirror of Apache Calcite - Avatica Go SQL Driver

Apache Avatica/Phoenix SQL Driver Apache Calcite's Avatica Go is a Go database/sql driver for the Avatica server. Avatica is a sub-project of Apache C

The Apache Software Foundation 103 Nov 3, 2022
Firebird RDBMS sql driver for Go (golang)

firebirdsql (Go firebird sql driver) Firebird RDBMS SQL driver for Go Requirements Firebird 2.5 or higher Golang 1.13 or higher

Hajime Nakagami 186 Dec 20, 2022
Microsoft ActiveX Object DataBase driver for go that using exp/sql

go-adodb Microsoft ADODB driver conforming to the built-in database/sql interface Installation This package can be installed with the go get command:

mattn 132 Dec 30, 2022
Oracle driver for Go using database/sql

go-oci8 Description Golang Oracle database driver conforming to the Go database/sql interface Installation Install Oracle full client or Instant Clien

mattn 598 Dec 30, 2022
sqlite3 driver for go using database/sql

go-sqlite3 Latest stable version is v1.14 or later not v2. NOTE: The increase to v2 was an accident. There were no major changes or features. Descript

mattn 6.3k Jan 8, 2023
GO DRiver for ORacle DB

Go DRiver for ORacle godror is a package which is a database/sql/driver.Driver for connecting to Oracle DB, using Anthony Tuininga's excellent OCI wra

null 409 Jan 5, 2023
Go Sql Server database driver.

gofreetds Go FreeTDS wrapper. Native Sql Server database driver. Features: can be used as database/sql driver handles calling stored procedures handle

minus5 108 Dec 16, 2022
PostgreSQL driver and toolkit for Go

pgx - PostgreSQL Driver and Toolkit pgx is a pure Go driver and toolkit for PostgreSQL. pgx aims to be low-level, fast, and performant, while also ena

Jack Christensen 6.5k Jan 4, 2023
Lightweight Golang driver for ArangoDB

Arangolite Arangolite is a lightweight ArangoDB driver for Go. It focuses on pure AQL querying. See AranGO for a more ORM-like experience. IMPORTANT:

Fabien Herfray 73 Sep 26, 2022
Go language driver for RethinkDB

RethinkDB-go - RethinkDB Driver for Go Go driver for RethinkDB Current version: v6.2.1 (RethinkDB v2.4) Please note that this version of the driver on

RethinkDB 1.6k Dec 24, 2022
goriak - Go language driver for Riak KV

goriak Current version: v3.2.1. Riak KV version: 2.0 or higher, the latest version of Riak KV is always recommended. What is goriak? goriak is a wrapp

Gustav Westling 29 Nov 22, 2022
Mongo Go Models (mgm) is a fast and simple MongoDB ODM for Go (based on official Mongo Go Driver)

Mongo Go Models Important Note: We changed package name from Kamva) to kamva) in v

kamva 607 Jan 2, 2023
The MongoDB driver for Go

The MongoDB driver for Go This fork has had a few improvements by ourselves as well as several PR's merged from the original mgo repo that are current

GlobalSign 2k Jan 8, 2023
The Go driver for MongoDB

MongoDB Go Driver The MongoDB supported driver for Go. Requirements Installation Usage Bugs / Feature Reporting Testing / Development Continuous Integ

mongodb 7.1k Dec 31, 2022
RethinkDB-go - RethinkDB Driver for Go

Go language driver for RethinkDB

RethinkDB 1.6k Dec 24, 2022