Is your feature request related to a problem? Please describe.
When a DB2 server is stopped or unreachable (e.g. firewall dropping packets, host down), sql.Open / sql.DB queries hang for 30-120 seconds waiting for the OS TCP timeout. Go's context.WithTimeout cannot help because:
- conn.go's Open() calls SQLDriverConnect which is a blocking CGO/C call. Go context cancellation cannot interrupt it.
- The context checks in PrepareContext(), ExecContext(), and QueryContext() (stmt.go) use a non-blocking select with default, so they only check if the context is already cancelled after the blocking ODBC call returns. they don't actually enforce the timeout during execution.
This makes it impossible to implement a fast-failing health check when DB2 is down. The only way to control the connection timeout is via the ODBC SQL_ATTR_LOGIN_TIMEOUT attribute, which must be set on the connection handle before calling SQLDriverConnect.
Describe the solution you'd like
Support a CONNECTTIMEOUT= keyword in the DSN connection string. When present, the driver should:
- Parse and extract CONNECTTIMEOUT from the DSN before passing it to SQLDriverConnect
- Call SQLSetConnectAttr(handle, SQL_ATTR_LOGIN_TIMEOUT, seconds, SQL_IS_UINTEGER) on the allocated connection handle before SQLDriverConnect
This leverages the existing api.SQLSetConnectUIntPtrAttr function already available in the codebase (used for SQL_ATTR_AUTOCOMMIT in tx.go).
Suggested implementation
In conn.go:
const SQL_ATTR_LOGIN_TIMEOUT api.SQLINTEGER = 103
func (d *Driver) Open(dsn string) (driver.Conn, error) {
var out api.SQLHANDLE
ret := api.SQLAllocHandle(api.SQL_HANDLE_DBC, api.SQLHANDLE(d.h), &out)
if IsError(ret) {
return nil, NewError("SQLAllocHandle", d.h)
}
h := api.SQLHDBC(out)
drv.Stats.updateHandleCount(api.SQL_HANDLE_DBC, 1)
// Parse and apply CONNECTTIMEOUT before connecting
cleanDsn, loginTimeout := extractConnectTimeout(dsn)
if loginTimeout > 0 {
ret = api.SQLSetConnectUIntPtrAttr(h, SQL_ATTR_LOGIN_TIMEOUT,
uintptr(loginTimeout), api.SQL_IS_UINTEGER)
if IsError(ret) {
defer releaseHandle(h)
return nil, NewError("SQLSetConnectUIntPtrAttr(SQL_ATTR_LOGIN_TIMEOUT)", h)
}
}
b := api.StringToUTF16(cleanDsn)
// ... rest of SQLDriverConnect unchanged ...
}
func extractConnectTimeout(dsn string) (string, int) {
parts := strings.Split(dsn, ";")
var cleaned []string
timeout := 0
for _, part := range parts {
trimmed := strings.TrimSpace(part)
if strings.HasPrefix(strings.ToUpper(trimmed), "CONNECTTIMEOUT") {
kv := strings.SplitN(trimmed, "=", 2)
if len(kv) == 2 {
if v, err := strconv.Atoi(strings.TrimSpace(kv[1])); err == nil && v > 0 {
timeout = v
}
}
} else {
cleaned = append(cleaned, part)
}
}
return strings.Join(cleaned, ";"), timeout
}
Usage
dsn := "HOSTNAME=myhost; UID=user; PWD=pass; DATABASE=mydb; PORT=50000; CONNECTTIMEOUT=5"
db, err := sql.Open("go_ibm_db", dsn)
If DB2 is unreachable, Open / first query will fail after 5 seconds instead of hanging for the OS TCP timeout.
Additional context
- SQL_ATTR_LOGIN_TIMEOUT (value 103) is a standard ODBC attribute supported by IBM CLI — see IBM documentation
- The same SQLSetConnectUIntPtrAttr pattern is already used in tx.go for SQL_ATTR_AUTOCOMMIT
- This is fully backward-compatible: DSNs without CONNECTTIMEOUT behave exactly as before
Tested with go_ibm_db v0.5.4 on Linux (clidriver)
Is your feature request related to a problem? Please describe.
When a DB2 server is stopped or unreachable (e.g. firewall dropping packets, host down), sql.Open / sql.DB queries hang for 30-120 seconds waiting for the OS TCP timeout. Go's context.WithTimeout cannot help because:
This makes it impossible to implement a fast-failing health check when DB2 is down. The only way to control the connection timeout is via the ODBC SQL_ATTR_LOGIN_TIMEOUT attribute, which must be set on the connection handle before calling SQLDriverConnect.
Describe the solution you'd like
Support a CONNECTTIMEOUT= keyword in the DSN connection string. When present, the driver should:
This leverages the existing api.SQLSetConnectUIntPtrAttr function already available in the codebase (used for SQL_ATTR_AUTOCOMMIT in tx.go).
Suggested implementation
In conn.go:
Usage
If DB2 is unreachable, Open / first query will fail after 5 seconds instead of hanging for the OS TCP timeout.
Additional context
Tested with go_ibm_db v0.5.4 on Linux (clidriver)