ase

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

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

Go to latest
Published: Apr 14, 2025 License: Apache-2.0 Imports: 19 Imported by: 0

README ¶

cgo-ase

PkgGoDev Go Report Card REUSE status

🛑 Repository Sunset Notice (2025-04-14)

Dear Contributers and Users,

This is an announcement that we are planning to officially sunset this repository. This decision was made after careful consideration of the project's current trajectory, community engagement, and resource allocation.

The sunset will happen after a grace period of four weeks following this announcement. Development and support will cease, and the project will be archived.

Thank You: We are grateful for your contributions and support.

For questions or concerns, please reach out.

Description

cgo-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.

cgo enables Go to call C code and to link against shared objects. A pure go implementation can be found here.

Requirements

The cgo driver requires the shared objects from either the ASE itself or Client-Library to compile.

The required shared objects from ASE can be found in the installation path of the ASE under OCS-16_0/lib, where 16_0 is the version of your ASE installation.

After installing the Client-Library SDK the shared objects can be found in the folder lib at the chosen installation path.

The headers are provided in the includes folder.

Aside from the shared object the cgo driver has no special requirements other than Go standard library and the third party 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/cgo-ase

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

The command-line application cgoase can be go installed:

$ go install github.com/SAP/cgo-ase/cmd/cgoase@latest
go: downloading github.com/SAP/cgo-ase v0.0.0-20210506101112-3f277f8e0603
$ cgoase -h
Usage of cgoase:
      --appname string        Application Name to transmit to ASE
      --database string       Database
  -f, --f string              Read SQL commands from file
      --host string           Hostname to connect to
      --key string            Key of userstore data to use for login
      --log-client-msgs       Log client messages
      --log-server-msgs       Log server messages
      --maxColLength int      Maximum number of characters to print for column (default 50)
      --password string       Password
      --port string           Port (Example: '443' or 'tls') to connect to
      --tls-hostname string   Expected server TLS hostname to pass to C driver
      --username string       Username
2021/05/06 11:00:22 cgoase failed: pflag: help requested

Usage

Example code:

package main

import (
    "database/sql"
    _ "github.com/SAP/cgo-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
    }
}

/path/to/OCS is the path to your Client-Library SDK installation. /lib is the folder inside of the SDK installation containing the shared objects required for the cgo driver.

Compilation
CGO_LDFLAGS="-L/path/to/OCS/lib" go build -o cgoase ./cmd/cgoase/
Execution
LD_LIBRARY_PATH="/path/to/OCS/lib:/path/to/OCS/lib3p:/path/to/OCS/lib3p64:" ./cgoase

While /path/to/OCS/lib contains the libraries of the Open Client, /path/to/OCS/lib3p and /path/to/OCS/lib3p64 contain the libraries needed to use ASE user store keys.

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_USERSTOREKEY
  • 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, configuration options in Client-Library 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

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

Each member of dblib.dsn.DsnInfo can be set using any of their possible json tags. E.g. .Host will receive the values from the keys host and hostname.

Additional properties are set as key/value pairs as well: ... prop1=val1 prop2=val2. If the parser doesn't recognize a string as a json tag it assumes that the key/value pair is a property and its value.

Similar to the URI DSN those property/value pairs are purely additive. Any property that only recognizes a single argument (e.g. a boolean) will only honour the last given value for a property.

Connector

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

package main

import (
    "database/sql"

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

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

    connector, err := ase.NewConnector(info)
    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 / app-name

Recognized values: string

When set overrides Client-Libraries default application name sent to the ASE server.

Userstorekey / userstorekey

Recognized values: string

When set uses the ASE userstore instead of username/password to authenticate with ASE.

TLSHostname / tls-hostname

Recognized values: string

Expected server TLS hostname to pass to Client-Library for validation.

LogClientMsgs / log-client-msgs

Recognized values: true or false

When set to true all client messages will be printed to stderr.

Please note that this is a debug property - for logging you should register your own message handler with the GlobalClientMessageBroker.

When unset the callback will not bet set.

LogServerMsgs / log-server-msgs

Recognized values: true or false

When set to true all server messages will be printed to stderr.

Please note that this is a debug property - for logging you should register your own message handler with the GlobalServerMessageBroker.

When unset the callback will not bet set.

Limitations

Prepared statements

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

Unsupported ASE data types

Currently the following data types are not supported:

  • Timestamp
  • Univarchar
Null types

Due to the limitations of the Client-Library it is not possible to support null types.

Additionally columns of the following data types must be nullable:

  • Image
  • Binary

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 cgo-ase driver for the database/sql package of Go (golang) to provide access to SAP ASE instances.

By using cgo this code is also enabled to call C code and to link against shared object. Thus, it is a shim to satisfy the databse/sql/driver-interface.

Index ¶

Constants ¶

View Source
const DriverName = "ase"

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

Variables ¶

View Source
var (
	// GlobalServerMessageBroker sends server messages to all registered
	// handlers.
	GlobalServerMessageBroker = newMessageBroker()
	// GlobalClientMessageBroker sends client messages to all registered
	// handlers.
	GlobalClientMessageBroker = newMessageBroker()
)

Functions ¶

func NewConnector ¶

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

NewConnector returns a new connector with the passed configuration.

func SetCallbackTarget ¶

func SetCallbackTarget(target *os.File)

SetCallbackTarget sets the os.File target the callback functions for client and server messages will write to.

Types ¶

type ASEType ¶

type ASEType byte

ASEType is the byte-representation of an ASE-datatype.

const (
	BIGDATETIME    ASEType = 35
	BIGINT         ASEType = 30
	BIGTIME        ASEType = 36
	BINARY         ASEType = 1
	BIT            ASEType = 11
	BLOB           ASEType = 26
	BOUNDARY       ASEType = 22
	CHAR           ASEType = 0
	DATE           ASEType = 27
	DATETIME       ASEType = 12
	DATETIME4      ASEType = 13
	DECIMAL        ASEType = 17
	FLOAT          ASEType = 10
	IMAGE          ASEType = 5
	IMAGELOCATOR   ASEType = 38
	INT            ASEType = 8
	LONG           ASEType = 20
	LONGBINARY     ASEType = 3
	LONGCHAR       ASEType = 2
	MONEY          ASEType = 14
	MONEY4         ASEType = 15
	NUMERIC        ASEType = 16
	REAL           ASEType = 9
	SENSITIVITY    ASEType = 21
	SMALLINT       ASEType = 7
	TEXT           ASEType = 4
	TEXTLOCATOR    ASEType = 37
	TIME           ASEType = 28
	TINYINT        ASEType = 6
	UBIGINT        ASEType = 33
	UINT           ASEType = 32
	UNICHAR        ASEType = 25
	UNITEXT        ASEType = 29
	UNITEXTLOCATOR ASEType = 39
	USER           ASEType = 100
	USHORT         ASEType = 24
	USMALLINT      ASEType = 31
	VARBINARY      ASEType = 19
	VARCHAR        ASEType = 18
	VOID           ASEType = 23
	XML            ASEType = 34
)

func (ASEType) String ¶

func (t ASEType) String() string

String returns the ASEType as string and satisfies the stringer interface.

func (ASEType) ToDataType ¶

func (t ASEType) ToDataType() asetypes.DataType

ToDataType returns the equivalent asetypes.DataType for an ASEType.

type ClientMessage ¶

type ClientMessage struct {
	Severity  int64
	MsgNumber uint64
	Text      string
	OSNumber  int64
	OSString  string
	Status    int64
	SQLState  string
}

ClientMessage is a message generated by Client-Library.

func (ClientMessage) Content ¶

func (msg ClientMessage) Content() string

Content returns the message-content of a client-message.

func (ClientMessage) MessageNumber ¶

func (msg ClientMessage) MessageNumber() uint64

MessageNumber returns the message-number of a client-message.

func (ClientMessage) MessageSeverity ¶

func (msg ClientMessage) MessageSeverity() int64

MessageSeverity returns the message-severity of a client-message.

type Command ¶

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

Command contains the C.command and indicates if that command is dynamic.

func (*Command) Cancel ¶

func (cmd *Command) Cancel() error

Cancel cancels the current result set.

func (*Command) ConsumeResponse ¶

func (cmd *Command) ConsumeResponse(ctx context.Context) (*Rows, *Result, error)

ConsumeResponse is a wrapper around .Response that guarantees that all results have been read.

func (*Command) Drop ¶

func (cmd *Command) Drop() error

Drop deallocates the command.

func (*Command) Response ¶

func (cmd *Command) Response() (*Rows, *Result, C.CS_INT, error)

Response reads a single response from the command structure and handles it.

When no more results are available this method returns io.EOF.

The third return value is a CS_INT, which may be the CS_RETCODE of ct_results when the command failed or finished or the result type if the result set requires further processing.

type Connection ¶

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

Connection implements the driver.Conn interface.

func NewConnection ¶

func NewConnection(driverCtx *csContext, info *Info) (*Connection, error)

NewConnection allocates a new connection based on the options in the dsn.

If driverCtx is nil a new csContext will be initialized.

func (*Connection) Begin ¶

func (conn *Connection) Begin() (driver.Tx, error)

Begin implements the driver.Conn interface.

func (*Connection) BeginTx ¶

func (conn *Connection) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error)

BeginTx implements the driver.ConnBeginTx interface.

func (*Connection) CheckNamedValue ¶

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

CheckNamedValue implements the driver.NamedValueChecker interface.

func (*Connection) Close ¶

func (conn *Connection) Close() error

Close implements the driver.Conn interface. It closes and deallocates a connection.

func (*Connection) Exec ¶

func (conn *Connection) Exec(query string, args []driver.Value) (driver.Result, error)

Exec implements the driver.Execer interface.

func (*Connection) ExecContext ¶

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

ExecContext implements the driver.ExecerContext interface.

func (*Connection) GenericExec ¶

func (conn *Connection) 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 (*Connection) NewCommand ¶

func (conn *Connection) NewCommand(ctx context.Context, query string) (*Command, error)

NewCommand creates a new command.

func (*Connection) Ping ¶

func (conn *Connection) Ping(ctx context.Context) error

Ping implements the driver.Pinger interface.

func (*Connection) Prepare ¶

func (conn *Connection) Prepare(query string) (driver.Stmt, error)

Prepare implements the driver.Conn interface.

func (*Connection) PrepareContext ¶

func (conn *Connection) PrepareContext(ctx context.Context, query string) (driver.Stmt, error)

PrepareContext implements the driver.ConnPrepareContext interface.

func (*Connection) Query ¶

func (conn *Connection) Query(query string, args []driver.Value) (driver.Rows, error)

Query implements the driver.Queryer interface.

func (*Connection) QueryContext ¶

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

QueryContext implements the driver.QueryerContext interface.

type Info ¶

type Info struct {
	dsn.Info

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

	Userstorekey string `json:"key" multiref:"userstorekey" doc:"Key of userstore data to use for login"`

	TLSHostname string `json:"tls-hostname" doc:"Expected server TLS hostname to pass to C driver"`

	LogClientMsgs bool `json:"log-client-msgs" doc:"Log client messages"`
	LogServerMsgs bool `json:"log-server-msgs" doc:"Log server messages"`
}

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 Message ¶

type Message interface {
	MessageNumber() uint64
	MessageSeverity() int64
	Content() string
}

Message defines the generic interface Server- und ClientMessage adhere to.

type MessageHandler ¶

type MessageHandler func(Message)

MessageHandler describes the signature of a handler for server- and client messages.

type MessageRecorder ¶

type MessageRecorder struct {
	Messages []string
	// contains filtered or unexported fields
}

MessageRecorder can be utilized to record non-SQL responses from the server.

See the example examples/recorder on how to utilize the MessageRecorder.

func NewMessageRecorder ¶

func NewMessageRecorder() *MessageRecorder

NewMessageRecorder returns an initialized MessageRecorder.

func (*MessageRecorder) HandleMessage ¶

func (rec *MessageRecorder) HandleMessage(msg Message)

HandleMessage implements the MessageHandler interface.

func (*MessageRecorder) Reset ¶

func (rec *MessageRecorder) Reset()

Reset prepares the MessageRecorder to record a new message.

func (*MessageRecorder) Text ¶

func (rec *MessageRecorder) Text() []string

Text returns the received messages.

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 {
	// 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) ColumnTypeLength ¶

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

ColumnTypeLength implements the driver.RowsColumnTypeLength interface.

func (*Rows) ColumnTypeMaxLength ¶

func (rows *Rows) ColumnTypeMaxLength(index int) int64

ColumnTypeMaxLength returns the maximum length of the column-datatype.

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 returns the datatype of the column.

func (*Rows) Columns ¶

func (rows *Rows) Columns() []string

Columns implements the driver.Rows interface.

func (*Rows) Next ¶

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

Next implements the driver.Rows interface.

type ServerMessage ¶

type ServerMessage struct {
	MsgNumber uint64
	State     int64
	Severity  int64
	Text      string
	Server    string
	Proc      string
	Line      int64
	SQLState  string
}

ServerMessage is a message sent from the ASE server to the client.

func (ServerMessage) Content ¶

func (msg ServerMessage) Content() string

Content returns the message-content of a server-message.

func (ServerMessage) MessageNumber ¶

func (msg ServerMessage) MessageNumber() uint64

MessageNumber returns the message-number of a server-message.

func (ServerMessage) MessageSeverity ¶

func (msg ServerMessage) MessageSeverity() int64

MessageSeverity returns the message-severity of a server-message.

Directories ¶

Path Synopsis
cmd
examples
genericexec
This example shows how to utilize the GenericExecer interface if both driver.Rows and driver.Result of a statement are required.
This example shows how to utilize the GenericExecer interface if both driver.Rows and driver.Result of a statement are required.
recorder
This example shows how the cgo.MessageRecorder can be used to process messages from the TDS server.
This example shows how the cgo.MessageRecorder can be used to process messages from the TDS server.
recorder2
This example shows how a custom recorder can be implemented to process messages from the TDS server.
This example shows how a custom recorder can be implemented to process messages from the TDS server.
simple
This example shows a simple interaction with a TDS server using the database/sql interface and the cgo-based driver.
This example shows a simple interaction with a TDS server using the database/sql interface and the cgo-based driver.
simple2
This example shows a simple interaction with a TDS server using the database/sql interface, prepared statements and the cgo-based driver.
This example shows a simple interaction with a TDS server using the database/sql interface, prepared statements and the cgo-based driver.

Jump to

Keyboard shortcuts

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