ase

package module
v0.0.0-...-e06baaf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2023 License: Apache-2.0 Imports: 14 Imported by: 1

README

go-ase

PkgGoDev Go Report Card REUSE status

Description

go-ase is a driver for the database/sql package of Go (golang) to provide access to SAP ASE instances. It is delivered as Go module.

SAP ASE is the shorthand for SAP Adaptive Server Enterprise, a relational model database server originally known as Sybase SQL Server.

A cgo implementation can be found here.

Requirements

The go driver has no special requirements other than Go standard library and the third part modules listed in go.mod, e.g. github.com/SAP/go-dblib.

Download and Installation

The packages in this repo can be go get and imported as usual, e.g.:

go get github.com/SAP/go-ase

For specifics on how to use database/sql please see the documentation.

The command-line application goase can be go installed:

$ go install github.com/SAP/go-ase/cmd/goase@latest
go: downloading github.com/SAP/go-ase v0.0.0-20210506093950-9af676a6bab4
$ goase -h
Usage of goase:
      --appname string                   Application Name to transmit to ASE (default "github.com/SAP/go-ase")
      --channel-package-queue-size int   How many TDS packages can be queued in a TDS channel (default 100)
      --client-hostname string           Hostname to send to server (default "dev-ase-sles15sp1-ntnn-1")
      --cursor-cache-rows int            How many rows to cache at once when reading the result set of a cursor (default 1000)
      --database string                  Database
      --debug-log-packages               Log packages as they are transmitted/received
  -f, --f string                         Read SQL commands from file
      --host string                      Hostname to connect to
      --maxColLength int                 Maximum number of characters to print for column (default 50)
      --network string                   Network to use, either 'tcp' or 'udp' (default "tcp")
      --no-query-cursor                  Prevents the use of cursors for database/sql query methods. See README for details.
      --packet-read-timeout int          Time in seconds to wait before aborting a connection when no response is received from the server (default 50)
      --password string                  Password
      --port string                      Port (Example: '443' or 'tls') to connect to
      --tls-ca-file string               Path to CA file to validate server certificate against
      --tls-enable                       Enforce TLS use
      --tls-hostname string              Remote hostname to validate against SANs
      --tls-skip-validation              Skip TLS validation - accepts any TLS certificate
      --username string                  Username
2021/05/06 11:31:44 goase failed: pflag: help requested

Usage

Example code:

package main

import (
    "database/sql"
    _ "github.com/SAP/go-ase"
)

func main() {
    db, err := sql.Open("ase", "ase://user:pass@host:port/")
    if err != nil {
        log.Printf("Failed to open database: %v", err)
        return
    }
    defer db.Close()

    if err := db.Ping(); err != nil {
        log.Printf("Failed to ping database: %v", err)
        return
    }
}
Compilation
go build -o goase ./cmd/goase/
Execution
./goase
Examples

More examples can be found in the folder examples.

Integration tests

Integration tests are available and can be run using go test --tags=integration and go test ./examples/... --tags=integration.

These require the following environment variables to be set:

  • ASE_HOST
  • ASE_PORT
  • ASE_USER
  • ASE_PASS

The integration tests will create new databases for each connection type to run tests against. After the tests are finished the created databases will be removed.

Configuration

The configuration is handled through either a data source name (DSN) in one of two forms or through a configuration struct passed to a connector.

All of these support additional properties which can tweak the connection or the drivers themselves.

Data Source Names
URI DSN

The URI DSN is a common URI like ase://user:pass@host:port/?prop1=val1&prop2=val2.

DSNs in this form are parsed using url.Parse.

Simple DSN

The simple DSN is a key/value string: username=user password=pass host=hostname port=4901

Each member of Info is recognized by its json metadata tag or any of its multiref metadata tags.

Values with spaces must be quoted using single or double quotes.

Connector

As an alternative to the string DSNs ase.NewConnector accept a Info directly and return a driver.Connector, which can be passed to sql.OpenDB:

package main

import (
    "database/sql"

    "github.com/SAP/go-ase"
)

func main() {
    info := ase.NewInfo()
    info.Host = "hostname"
    info.Port = "4901"
    info.Username = "user"
    info.Password = "pass"

    connector, err := ase.NewConnector(d)
    if err != nil {
        log.Printf("Failed to create connector: %v", err)
        return
    }

    db, err := sql.OpenDB(connector)
    if err != nil {
        log.Printf("Failed to open database: %v", err)
        return
    }
    defer db.Close()

    if err := db.Ping(); err != nil {
        log.Printf("Failed to ping ASE: %v", err)
    }
}
Properties
appname

Recognized values: string

Sets the application name to the value. This can be used in ASE to determine which application opened a connection.

Defaults to database/sql driver github.com/SAP/go-ase/purego.

network

Recognized values: string

The network must be a network type recognized by net.Dial - at the time of writing this is either udp or tcp.

This should only be required to be set if the database is only reachable through a UDP proxy.

Defaults to tcp.

channel-package-queue-size

Recognized values: integer

Defines how many packages a TDS channel can buffer at most. When working with very large datasets where heavy computation only occurs every hundred packages or so it may be feasible to improve performance by increasing the queue size.

Defaults to 100.

client-hostname

Recognized values: string

The client-hostname to report to the TDS server. Due to protocol limitations this will be cut off after 30 characters.

Defaults to the hostname of the machine, acquired using os.Hostname.

packet-read-timeout

Recognized values: integer

The timeout in seconds when a packet is read. The timeout is reset every time a packet successfully reads data from the connection.

That means the timeout only triggers if no data was read for longer than packet-read-timeout seconds.

Default to 50.

tls

Recognized values: bool

Activates TLS for the connection. Any other TLS option is ignored unless tls is set to true.

Defaults to true if the target port is 443, false otherwise.

tls-hostname

Recognized values: string

Allows to pass SAN for TLS validation.

For compatibility with the cgo implementation you may also use ssl instead of tls-hostname and pass CN=<SAN> instead of <SAN>.

Defaults to empty string.

Please note that as of go1.15 the CommonName in x509 certificates is no longer recognized as the hostname if no SANs are present in the certificate. If the certificate for your TDS server only utilizes the CN you can reenable this behaviour by setting GODEBUG to x509ignoreCN=0 in your environment:

GODEBUG=x509ignoreCN=0 <path/to/your/app>
GODEBUG=x509ignoreCN=0 go run ./cmd/goase

For details see https://golang.google.cn/doc/go1.15#commonname

tls-skip-validation

Recognized values: string

If the value is recognized by strconv.ParseBool to represent true the TLS certificate of the TDS server will not be validated.

Defaults to empty string / false.

tls-ca

Recognized values: string

Path to a CA file, which may contain multiple CAs, to validate the TDS servers certificate against. If empty the servers trust store is used.

Defaults to empty string.

no-query-cursor

Recognized values: bool

Prevents the use of cursors for database/sql query methods.

By default go-ase creates cursors when a .Query* method is used.

Depending on the query, expected result set, memory consumption and used hardware this may perform worse than a simple query.

It is strongly suggested to profile this option with your queries before enabling it.

Altneratively you can pass this option on a per-query basis in the context. See the documentation of Conn.QueryContext for details.

Nullable data types

Nullable data types are implemented in go-dblib. However, the implementation differs partially from drivers like isql in regard of "zero-length non-Null" string-types, e.g. "". Instead of inserting such values as " ", the methods stmt.Exec(...) or db.Exec(...) will insert these values as actual NULL values. A legacy-option to insert such "zero-length non-Null" string-type values as " " is planned but not implemented yet. In the meantime, it is possible to reproduce this behaviour by using language tokens as provided by the executable goase.

Limitations

Beta

The go implementation is currently in beta and under active development. As such most features of the TDS protocol and ASE are not supported.

Prepared statements

Regarding the limitations of prepared statements/dynamic SQL please see the Client-Library documentation.

The Client-Library documentation applies to the go implementation as these restrictions are imposed by the implementation of dynamic SQL on the server side.

Unsupported ASE data types

Currently the following data types are not supported:

  • Timestamp
  • Univarchar
  • Nullable Text
  • Nullable Unitext
  • Nullable Unichar
  • Nullable Image

Known Issues

The list of known issues is available here.

How to obtain support

Feel free to open issues for feature requests, bugs or general feedback here.

Contributing

Any help to improve this package is highly appreciated.

For details on how to contribute please see the contributing file.

License

Copyright (c) 2019-2020 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache License 2.0 except as noted otherwise in the LICENSE file.

Documentation

Overview

Package ase contains code of the go-ase driver for the database/sql package of Go (golang) to provide access to SAP ASE instances.

Index

Constants

View Source
const DriverName = "ase"

DriverName is the driver name to use with sql.Open for ase databases.

Variables

View Source
var (
	ErrCurNoMoreRows = errors.New("no more rows in cursor")
)

Functions

func AddEEDHooks

func AddEEDHooks(fns ...tds.EEDHook) error

AddEEDHooks registers functions as hooks. The hooks are executed when the driver receives EED packages.

func AddEnvChangeHooks

func AddEnvChangeHooks(fns ...tds.EnvChangeHook) error

AddEnvChangeHooks registers funtions as hooks. The hooks are executed when the driver receives EnvChange packages.

func DefaultTxOptions

func DefaultTxOptions() driver.TxOptions

DefaultTxOptions returns default driver.TxOptions.

func NewConnector

func NewConnector(info *Info) (driver.Connector, error)

NewConnector returns a new connector with the passed configuration.

func NewConnectorWithHooks

func NewConnectorWithHooks(info *Info, envChangeHooks []tds.EnvChangeHook, eedHooks []tds.EEDHook) (driver.Connector, error)

NewConnectorWithHooks returns a new connector with the passed configuration.

Types

type Conn

type Conn struct {
	Conn    *tds.Conn
	Channel *tds.Channel
	Info    *Info
	// contains filtered or unexported fields
}

Conn implements the driver.Conn interface.

func NewConn

func NewConn(ctx context.Context, dsn *Info) (*Conn, error)

NewConn returns a connection with the passed configuration.

func NewConnWithHooks

func NewConnWithHooks(ctx context.Context, info *Info, envChangeHooks []tds.EnvChangeHook, eedHooks []tds.EEDHook) (*Conn, error)

NewConnWithHooks returns a connection with the passed configuration.

func (*Conn) Begin

func (c *Conn) Begin() (driver.Tx, error)

Begin implements the driver.Conn interface.

func (*Conn) BeginTx

func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)

BeginTx implements the driver.ConnBeginTx interface.

func (*Conn) CheckNamedValue

func (conn *Conn) CheckNamedValue(nv *driver.NamedValue) error

CheckNamedValue implements the driver.NamedValueChecker interface.

func (*Conn) Close

func (c *Conn) Close() error

Close implements the driver.Conn interface.

func (*Conn) DirectExec

func (c *Conn) DirectExec(ctx context.Context, query string, args ...interface{}) (driver.Rows, driver.Result, error)

DirectExec is a wrapper for GenericExec and meant to be used when directly accessing this library, rather than using database/sql.

The primary advantage are the variadic args, which can be normal values and are automatically transformed to driver.NamedValues for GenericExec.

func (*Conn) ExecContext

func (c *Conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error)

ExecContext implements the driver.ExecerContext.

func (*Conn) GenericExec

func (c *Conn) GenericExec(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, driver.Result, error)

GenericExec is the central method through which SQL statements are sent to ASE.

func (*Conn) NewCursor

func (c *Conn) NewCursor(ctx context.Context, query string, args ...interface{}) (*Cursor, error)

NewCursor creates a new cursor.

NewCursor is a wrapper around NewCursorWithValues that converts arguments into driver.NamedValues.

func (*Conn) NewCursorWithValues

func (c *Conn) NewCursorWithValues(ctx context.Context, query string, args []driver.NamedValue) (*Cursor, error)

NewCursorWithValues creates a new cursor.

func (*Conn) NewRows

func (conn *Conn) NewRows() *Rows

func (*Conn) NewStmt

func (c *Conn) NewStmt(ctx context.Context, name, query string, create_proc bool) (*Stmt, error)

NewStmt creates a new statement.

func (*Conn) NewTransaction

func (c *Conn) NewTransaction(ctx context.Context, opts driver.TxOptions, name string) (*Transaction, error)

NewTransaction creates a new transaction.

func (Conn) Ping

func (c Conn) Ping(ctx context.Context) error

Ping implements the driver.Pinger interface.

func (*Conn) Prepare

func (c *Conn) Prepare(query string) (driver.Stmt, error)

Prepare implements the driver.Conn interface.

func (*Conn) PrepareContext

func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)

PrepareContext implements the driver.ConnPrepareContext interface.

func (*Conn) QueryContext

func (c *Conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error)

QueryContext implements the driver.QueryerContext.

QueryContext utilizes cursors unless c.Info.NoQueryCursor is set or the context has the value "NoQueryContext" set to true.

If the context has NoQueryCursor set it overrides c.Info.NoQueryCursor.

type Connector

type Connector struct {
	Info           *Info
	EnvChangeHooks []tds.EnvChangeHook
	EEDHooks       []tds.EEDHook
}

Connector implements the driver.Connector interface.

func (*Connector) Connect

func (c *Connector) Connect(ctx context.Context) (driver.Conn, error)

Connect implements the driver.Connector interface.

func (Connector) Driver

func (c Connector) Driver() driver.Driver

Driver implements the driver.Connector interface.

type Cursor

type Cursor struct {
	// contains filtered or unexported fields
}

Cursor is used to interact with a cursor on the ASE server.

func (*Cursor) Close

func (cursor *Cursor) Close(ctx context.Context) error

Close closes the cursor.

func (Cursor) CursorID

func (cursor Cursor) CursorID() int

CursorID returns the ID assigned to the cursor by ASE.

func (*Cursor) Fetch

func (cursor *Cursor) Fetch(ctx context.Context) (*CursorRows, error)

Fetch returns CursorRows to iterate over the rows selected by a cursor.

func (*Cursor) NewCursorRows

func (cursor *Cursor) NewCursorRows() (*CursorRows, error)

NewCursorRows returns CursorRows for a Cursor.

It does not immediately fetch a result set from the remote. See .Fetch.

type CursorRows

type CursorRows struct {
	// contains filtered or unexported fields
}

CursorRows is used to iterate over the result set of a cursor.

func (*CursorRows) Close

func (rows *CursorRows) Close() error

Close closes CursorRows and its associated Cursor.

func (CursorRows) ColumnTypeDatabaseTypeName

func (rows CursorRows) ColumnTypeDatabaseTypeName(index int) string

ColumnTypeDatabaseTypeName implements the driver.RowsColumnTypeDatabaseTypeName interface.

func (CursorRows) ColumnTypeDisplayLength

func (rows CursorRows) ColumnTypeDisplayLength(index int) (int64, bool)

ColumnTypeDisplayLength returns a best guess of the maximum length required to display the values of the column.

func (CursorRows) ColumnTypeLength

func (rows CursorRows) ColumnTypeLength(index int) (int64, bool)

ColumnTypeLength implements the driver.RowsColumnTypeLength interface.

func (CursorRows) ColumnTypeNullable

func (rows CursorRows) ColumnTypeNullable(index int) (bool, bool)

ColumnTypeNullable implements the driver.RowsColumnTypeNullable interface.

func (CursorRows) ColumnTypePrecisionScale

func (rows CursorRows) ColumnTypePrecisionScale(index int) (int64, int64, bool)

ColumnTypePrecisionScale implements the driver.RowsColumnTypePrecisionScale interface.

func (CursorRows) ColumnTypeScanType

func (rows CursorRows) ColumnTypeScanType(index int) reflect.Type

ColumnTypeScanType implements the driver.RowsColumnTypeScanType interface.

func (CursorRows) Columns

func (rows CursorRows) Columns() []string

Columns implements the driver.Rows interface.

func (*CursorRows) Next

func (rows *CursorRows) Next(dst []driver.Value) error

Next implements driver.Rows.

type Driver

type Driver struct {
	// contains filtered or unexported fields
}

Driver implements the driver.Driver interface.

func (Driver) Open

func (d Driver) Open(name string) (driver.Conn, error)

Open implements the driver.Driver interface.

func (Driver) OpenConnector

func (d Driver) OpenConnector(name string) (driver.Connector, error)

OpenConnector implements the driver.DriverContext interface.

type Info

type Info struct {
	tds.Info

	AppName string `json:"appname" doc:"Application Name to transmit to ASE"`

	NoQueryCursor bool `json:"no-query-cursor" doc:"Prevents the use of cursors for database/sql query methods. See README for details."`

	CursorCacheRows int `json:"cursor-cache-rows" doc:"How many rows to cache at once when reading the result set of a cursor"`
}

func NewInfo

func NewInfo() (*Info, error)

NewInfo returns a bare Info for github.com/SAP/go-dblib/dsn with defaults.

func NewInfoWithEnv

func NewInfoWithEnv() (*Info, error)

NewInfoWithEnv is a convenience function returning an Info with values filled from the environment with the prefix 'ASE'.

func NewInfoWithFlags

func NewInfoWithFlags() (*Info, *flag.FlagSet, error)

NewInfoFlags is a convenience function returning an Info filled with defaults and a flagset with flags bound to the members of the returned info.

type NoQueryCursor

type NoQueryCursor bool

type Result

type Result struct {
	// contains filtered or unexported fields
}

Result implements the driver.Result interface.

func (Result) LastInsertId

func (result Result) LastInsertId() (int64, error)

LastInsertId implements the driver.Result interface.

func (Result) RowsAffected

func (result Result) RowsAffected() (int64, error)

RowsAffected implements the driver.Result interface.

type Rows

type Rows struct {
	Conn *Conn

	RowFmt *tds.RowFmtPackage
	// contains filtered or unexported fields
}

Rows implements the driver.Rows interface.

func (*Rows) Close

func (rows *Rows) Close() error

Close implements the driver.Rows interface.

func (Rows) ColumnTypeDatabaseTypeName

func (rows Rows) ColumnTypeDatabaseTypeName(index int) string

ColumnTypeDatabaseTypeName implements the driver.RowsColumnTypeDatabaseTypeName interface.

func (Rows) ColumnTypeDisplayLength

func (rows Rows) ColumnTypeDisplayLength(index int) (int64, bool)

ColumnTypeDisplayLength returns a best guess of the maximum length required to display the values of the column.

func (Rows) ColumnTypeLength

func (rows Rows) ColumnTypeLength(index int) (int64, bool)

ColumnTypeLength implements the driver.RowsColumnTypeLength interface.

func (Rows) ColumnTypeNullable

func (rows Rows) ColumnTypeNullable(index int) (bool, bool)

ColumnTypeNullable implements the driver.RowsColumnTypeNullable interface.

func (Rows) ColumnTypePrecisionScale

func (rows Rows) ColumnTypePrecisionScale(index int) (int64, int64, bool)

ColumnTypePrecisionScale implements the driver.RowsColumnTypePrecisionScale interface.

func (Rows) ColumnTypeScanType

func (rows Rows) ColumnTypeScanType(index int) reflect.Type

ColumnTypeScanType implements the driver.RowsColumnTypeScanType interface.

func (Rows) Columns

func (rows Rows) Columns() []string

Columns implements the driver.Rows interface.

func (*Rows) HasNextResultSet

func (rows *Rows) HasNextResultSet() bool

HasNextResultSet implements the driver.RowsNextResultSet interface.

func (*Rows) Next

func (rows *Rows) Next(dst []driver.Value) error

Next implements the driver.Rows interface.

func (*Rows) NextResultSet

func (rows *Rows) NextResultSet() error

NextResultSet implements the driver.RowsNextResultSet interface.

type Stmt

type Stmt struct {
	// contains filtered or unexported fields
}

Stmt implements the driver.Stmt interface.

func (Stmt) CheckNamedValue

func (stmt Stmt) CheckNamedValue(nv *driver.NamedValue) error

CheckNamedValue implements the driver.NamedValueChecker interface.

func (*Stmt) Close

func (stmt *Stmt) Close() error

Close implements the driver.Stmt interface.

func (Stmt) DirectExec

func (stmt Stmt) DirectExec(ctx context.Context, args ...interface{}) (driver.Rows, driver.Result, error)

DirectExec is a wrapper for GenericExec and meant to be used when directly accessing this library, rather than using database/sql.

The primary advantage are the variadic args, which can be normal values and are automatically transformed to driver.NamedValues for GenericExec.

func (Stmt) Exec

func (stmt Stmt) Exec(args []driver.Value) (driver.Result, error)

Exec implements the driver.Stmt interface.

func (Stmt) ExecContext

func (stmt Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error)

ExecContext implements the driver.StmtExecContext interface.

func (Stmt) GenericExec

func (stmt Stmt) GenericExec(ctx context.Context, args []driver.NamedValue) (driver.Rows, driver.Result, error)

GenericExec is the central method through which SQL statements are sent to ASE.

func (Stmt) NumInput

func (stmt Stmt) NumInput() int

NumInput implements the driver.Stmt interface.

func (Stmt) Query

func (stmt Stmt) Query(args []driver.Value) (driver.Rows, error)

Query implements the driver.Stmt interface.

func (Stmt) QueryContext

func (stmt Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error)

QueryContext implements the driver.StmtQueryContext interface.

func (*Stmt) Reset

func (stmt *Stmt) Reset()

Reset resets a statement.

type Transaction

type Transaction struct {
	// contains filtered or unexported fields
}

Transaction implements the driver.Tx interface.

func (Transaction) Commit

func (tx Transaction) Commit() error

Commit implements the driver.Tx interface.

func (Transaction) Name

func (tx Transaction) Name() string

Name returns the name of the transaction.

func (Transaction) NewTransaction

func (tx Transaction) NewTransaction(ctx context.Context, opts driver.TxOptions) (*Transaction, error)

NewTransaction creates a new transaction.

func (Transaction) Rollback

func (tx Transaction) Rollback() error

Rollback implements the driver.Tx interface.

Directories

Path Synopsis
cmd
columnTypes
This example shows how to retrieve column type information.
This example shows how to retrieve column type information.
cursor
This example shows how to use cursor with the go-ase driver.
This example shows how to use cursor with the go-ase driver.
directExec
This example shows how to utilize the DirectExecer interface to receive both the driver.Rows and driver.Result of a SQL query.
This example shows how to utilize the DirectExecer interface to receive both the driver.Rows and driver.Result of a SQL query.
eedexample
This example shows how to retrieve the wrapped tds.EEDError to access messages sent by the TDS server in the context of an SQL statement.
This example shows how to retrieve the wrapped tds.EEDError to access messages sent by the TDS server in the context of an SQL statement.
noQueryCursor
go-ase uses cursor by default for all SQL queries.
go-ase uses cursor by default for all SQL queries.
preparedStatement
This example shows a simple interaction with a TDS server using the database/sql interface, prepared statements and the pure go driver.
This example shows a simple interaction with a TDS server using the database/sql interface, prepared statements and the pure go driver.
recorder
This example shows how tds.EEDHooks can be utilized to record and inspect a number of tds.EEDPackages received during a transaction.
This example shows how tds.EEDHooks can be utilized to record and inspect a number of tds.EEDPackages received during a transaction.
simple
This example shows a simple interaction with a TDS server using the database/sql interface and the pure go driver.
This example shows a simple interaction with a TDS server using the database/sql interface and the pure go driver.
template
TODO describe what the example does or shows here
TODO describe what the example does or shows here
transaction
This example shows the use of transactions using the database/sql interface and the pure go driver.
This example shows the use of transactions using the database/sql interface and the pure go driver.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL