Qore sybase and freetds Modules: Qore sybase Module

| Qore sybase and freetds Modules 1.2

Loading...
Searching...
No Matches
Qore sybase Module

# Introduction to the sybase and freetds Modules

Both the `sybase` and `freetds` modules are built from the same sources; this documentation will describe both modules. They share most of their functionality, but there are differences, both depending on the client libraries used, and according to the database server connected.

The `sybase` and `freetds` modules provide drivers to Qore's DBI system, allowing Qore programs to access Sybase (both modules) databases and Microsoft SQL Server (the `freetds` module) through the Datasource, DatasourcePool, and SQLStatement classes.

Both modules are released under a choice of two licenses:

- LGPL 2.1
- MIT (see COPYING.MIT in the source distribution for more information)

Both modules are tagged as such in the modules' headers (meaning they can be loaded unconditionally regardless of how the Qore library was initialized).

Example of creating a connection with the `sybase` driver:

Datasource db("sybase:user/pass@dbname(utf8):host:4100");

Example of creating a connection with the `freetds` driver:

Datasource db("freetds:user/pass@dbname(utf8):host:1433");

This driver supports the following DBI capabilities:

- `DBI_CAP_TIME_ZONE_SUPPORT`
- `DBI_CAP_TRANSACTION_MANAGEMENT`
- `DBI_CAP_CHARSET_SUPPORT`
- `DBI_CAP_LOB_SUPPORT`
- `DBI_CAP_STORED_PROCEDURES`
- `DBI_CAP_BIND_BY_VALUE`
- `DBI_CAP_HAS_EXECRAW`
- `DBI_CAP_HAS_STATEMENT`
- `DBI_CAP_HAS_SELECT_ROW`
- `DBI_CAP_HAS_NUMBER_SUPPORT`
- `DBI_CAP_HAS_OPTION_SUPPORT`
- `DBI_CAP_SERVER_TIME_ZONE`
- `DBI_CAP_AUTORECONNECT`

The driver employs efficient binary bindings for all non-text data types.

The Datasource::getServerVersion() and Datasource::getClientVersion() methods are implemented for both drivers. Datasource::getServerVersion() returns a string giving server information similar to the following:

    Adaptive Server Enterprise/15.0.1/EBF 13827/P/x86_64/Enterprise Linux/ase1501/2379/64-bit/OPT/Mon Aug 14 22:15:25 2006

Or for freetds with MS SQL Server:

    Microsoft SQL Server 2014 (RTM-CU14) (KB3158271) - 12.0.2569.0 (X64)
    	May 27 2016 15:06:08
    	Copyright (c) Microsoft Corporation
    	Express Edition (64-bit) on Windows NT 6.3 <X64> (Build 10586: )

The Datasource::getClientVersion() returns a string giving version information. For example, for freetds:

    freetds v1.0 (threadsafe, default tds version=auto)

Or for Sybase:

    Sybase Client-Library/15.0/P-EBF13571 ESD #4/DRV.15.0.1/Linux x86_64/Linux 2.4.21-27.ELsmp x86_64/BUILD1500-073/OPT/Mon May 15 03:18:58 2006

## SQL Statement Execution

This driver allows all types of statements to be executed through Datasource::select(), Datasource::selectRows(), and Datasource::exec() (and related methods), however rules about Datasource locking or DatasourcePool allocations still apply as usual. If a stored procedure is executed with Datasource::selectRows(), then any query results returned will be returned in either a hash format (if only one row was returned), or as a list of hashes (for multiple rows).

The TDS protocol only supports a single active query on a connection at one time, therefore there can be only one SQLStatement object active at any one time on a single server connection; if additional SQL commands or a new SQLStatement is executed while another SQLStatement is active, the existing statement will be canceled before starting the new statement.

Unlike many other Qore DBI drivers, this driver allows and can return results from multiple select statements issued with a single call. Additionally, it's possible for a stored procedure to return output paramters as well as one or more result sets from select statements. The output format for commands like this differs from standard Qore DBI formats as follows:

Query Type | Result Format
Multiple Selects | A hash is returned with a key giving the results from each select statement. The key names have the format `query`#, where # is an increasing integer starting with 0.
Return Parameters Only | A hash is returned with keys giving the output parameter values, as long as the placeholder format (ex: ``:name) was used for the output parameters, otherwise the key names in the output will be an increasing integer starting with 0 (i.e. 0, 1, etc). If a count of affected rows is available, it's returned in the `rowcount` key.
Return Parameters and Result Set(s) | As above, but with an addition key: `query`, giving the result set. If multiple result sets are returned, then the `query` key will be a hash with `query#` keys giving the results for each query in order.

# sybase and freetds Driver Options

The `sybase` and `freetds` drivers support the following DBI options:

- `"optimal-numbers"`: return numeric types as an integer if possible, if not as an arbitrary-precision number
- `"string-numbers"`: return numeric types as strings (for backwards-compatibility)
- `"numeric-numbers"`: return numeric types as arbitrary-precision number values
- `"timezone"`: accepts a string argument that can be either a region name (ex: `"Europe/Prague"`) or a UTC offset (ex: `"+01:00"`) to set the server's time zone rules; this is useful if connecting to a database server in a different time zone. If this option is not set then the server's time zone is assumed to be the same as the client's time zone; see timezone.
- `"optimized-date-binds"`: when set, date/time values are bound with full resolution including microseconds, however this will cause any operations with date/time values with microseconds bound for `DATETIME` columns to fail; if this is not set, then date/time values are bound with an approach that works for all columns but gives a maximum of 1/300 second resolution

Options can be set in the Qore::SQL::Datasource or Qore::SQL::DatasourcePool constructors as in the following examples:

Dataource ds("sybase:user/pass@db{numeric-numbers,timezone=Europe/Vienna}");
DataourcePool dsp("freetds:user/pass@db%host.internal:1433{optimal-numbers}");

Options are stored separately for each connection.

## Number Options

The number options (`"optimal-numbers"`, `"string-numbers"`, and `"numeric-numbers"`) are all mutually-exclusive; setting one automatically disables the others. These options also ignore their arguments; the last one set takes effect (also note that setting it with any value sets the option, even False).

The default if no other option is explicitly set is `"optimal-numbers"`. Note that this represents a change from previous versions where `NUMERIC` or `DECIMAL` values were returned as strings in order to avoid the loss of information. To set the old behavior, set the `"string-numbers"` option when creating the `Datasource` or `DatasourcePool` object.

`NUMERIC` or `DECIMAL` output values:

- `"optimal-numbers"`: return numeric values as an integer if possible, if not as an arbitrary-precision number
- `"string-numbers"`: return numeric values as strings (for backwards-compatibility)
- `"numeric-numbers"`: return numeric values as arbitrary-precision number values

# Transaction Management

Transaction management is supported by enabling chained transaction mode on each connection. In autocommit mode in the Qore::SQL::Datasource class, Qore executes a commit after every request to the server.

The transaction isolation level is left at the default, 1, `"read committed"`, which is the default for all Qore drivers as well.

# Time Zone Support

The driver now sets the server's time zone rules when the connection is established; this is taken from the current time zone settings of the calling Program object and can also be overridden/changed by setting the `"timezone"` driver option (see sybase and freetds Driver Options).

All date/time values bound by value are converted to the server's time zone before binding to ensure that date/time values are stored correctly in the server.

When selecting date/time values, the values returned are tagged with the server's time zone.

Note that the above rules are applied when the current Program's time zone settings are different than the connection's time zone settings at the time when the write operation (bind) read operation (select) is performed. This is meant to provide consistent support to connecting to a database server in a different time zone.

# Binding and Types

Note that binding by placeholder is not required or supported by this driver as values are returned directly; Qore DBI placeholder buffer specifications are ignored when the `sybase` and `freetds` drivers are used.

When retrieving data, data types are converted to Qore types as per Database to Qore Type Mappings.

## Binding by Value

`DATETIME` and `TIME` data types have a resolution of 1/300th of a second. Qore uses floating-point operations to convert to or from microseconds when binding and retrieving data and rounds to the nearest integer to minimize conversion errors.

### Binding by Value with the sybase Driver

The following table gives data mapping when binding qore types by value with the `sybase` driver.

QoreType | sybase Type | Description
`Type::Int` | `CS_BIGINT_TYPE` | Sybase's integer type is only 32 bits, integers greater than 2147483647 bound to an `INT` column will only have their lower 32 bits saved to Sybase.
`Type::Float` | `CS_FLOAT_TYPE` | direct conversion
`Type::Boolean` | `CS_BIT_TYPE` | True = 1, False = 0
`Type::String` | `CS_CHAR_TYPE` | direct conversion
`Type::Date` | `CS_DATETIME_TYPE` | milliseconds are rounded to 1/300 second values
`Type::Binary` | `CS_BINARY_TYPE` | direct conversion

### Binding by Value with the freetds Driver

The following table gives data mapping when binding qore types by value with the `freetds` driver.

QoreType | freetds Type | Description
`Type::Int` | `CS_BIGINT_TYPE`, `CS_INT_TYPE` or `CS_FLOAT_TYPE` | Integer type is only 32-bits, integers greater than 2147483647 bound to an `INT` column will only have their lower 32 bits saved to the database. If the ~FreeTDS version used to compile this driver does not support `CS_BIGINT_TYPE`, then integers 32 bits or smaller will be bound as `CS_INT_TYPE`, and larger integers will be bound as `CS_FLOAT_TYPE`.
`Type::Float` | `CS_FLOAT_TYPE` | direct conversion
`Type::Boolean` | `CS_BIT_TYPE` | True = 1, False = 0
`Type::String` | `CS_CHAR_TYPE` | direct conversion
`Type::Date` | `CS_DATETIME_TYPE` | milliseconds are rounded to 1/300 second values
`Type::Binary` | `CS_BINARY_TYPE` | direct conversion

## Database to Qore Type Mappings

Data Type | Qore Type | Driver | Notes
`TINYINT` | Qore::Type::Int | both | direct conversion
`SMALLINT` | Qore::Type::Int | both | direct conversion
`INT` | Qore::Type::Int | both | direct conversion
`BIGINT` | Qore::Type::Int | both | direct conversion
`DECIMAL`, NUMERIC | depends on options | both | see Number Options
`FLOAT` | Qore::Type::Float | both | direct conversion
`REAL` | Qore::Type::Float | both | direct conversion
`MONEY` | Qore::Type::Float | both | direct conversion
`SMALLMONEY` | Qore::Type::Float | both | direct conversion
`DATETIME` | Qore::Type::Date | both | 1/300 second values are converted and rounded to the nearest microsecond
`SMALLDATETIME` | Qore::Type::Date | both | direct conversion
`DATE` | Qore::Type::Date | both | direct conversion
`TIME` | Qore::Type::Date | sybase | Date portion is set to '1970-01-01'; 1/300 second values are converted and rounded to the nearest microsecond
`TIME` | Qore::Type::Date | freetds | currently returned as a string with MS SQL Server DBs
`CHAR` | Qore::Type::String | both | trailing blanks are removed
`VARCHAR` | Qore::Type::String | both | direct conversion
`UNICHAR` | Qore::Type::String | sybase | trailing blanks are removed
`UNIVARCHAR` | Qore::Type::String | sybase | trailing blanks are removed
`TEXT` | Qore::Type::String | both | direct conversion
`UNITEXT` | Qore::Type::Binary | both | this data is returned as type `IMAGE` from the dataserver, so a binary object is returned by the driver
`BINARY` | Qore::Type::Binary | both | direct conversion
`VARBINARY` | Qore::Type::Binary | both | direct conversion
`IMAGE` | Qore::Type::Binary | both | direct conversion

# Stored Procedures

Stored procedure execution is supported, the following is an example of a stored procedure call with output parameters:

    create procedure get_values @string varchar(80) output, @int int output
    as
    select @string = 'hello there'
    select @int = 150
    commit -- to maintain transaction count

Qore code to call this procedure:

# note that if the output parameters are declared as @string and @int, the driver cannot
# return the parameter result hash with key names corresponding to the param names.
# ":string" and ":int" is qore placeholder syntax, consistent with other Qore DBI
# driver placeholder syntax
hash result = db.exec("declare @string varchar(40), @int int
exec get_values :string output, :int output");

Note
  FreeTDS Limitations
  The `freetds` driver is not able to retrieve output parameter values when executing queries on MS SQL Server 2000 or above (tds version 5.0 or above), due to the fact that newer MS SQL Server dataservers no longer return output parameter information through the TDS protocol as with Sybase and previous versions of SQL Server. A future version of this driver should offer an alternative Datasource method allowing explicit stored procedure execution through ct-lib RPC functions, which will allow output parameters to be returned.
  There are other issues with data types, character encoding, and more when using this driver; please see http://www.freetds.org for more information

# Release Notes

## sybase Driver Version 1.2

- detect and automatically set the server character encoding for MS SQL server connections to ensure that strings with invalid encodings are never sent to or retrieved from the server (issue 4710)

## sybase Driver Version 1.1

- fixed a bug handliing `DATETIME2` column data (issue 4401)
- implemented the `"optimized-date-binds"` option

## sybase Driver Version 1.0.4.2

- fixed support for newer freetds versions that return a 2GB size for text columns with MS SQL Server (issue 4129)
- added support for `BIGDATETIME`, `BIGDATE`, and `BIGTIME` columns (issue 3951)
- fixed a build issue where the `FREETDS` environment variable was not respected as documented (issue 2017)
- fixed a memory error that could result in a crash when a freetds connection is made with the incorrect `tds version` (issue 2689)
- added support for the selectRow() method (issue 2690)

## sybase Driver Version 1.0.4.1

New Features and Bug Fixes

- updated SQLStatement::fetchColumns() to return an empty hash when no data is available (issue 1241)
- fixed bugs handling SQLStatements used with this driver; the TDS protocol only allows one active query at a time, so any active statements have to be canceled before executing new SQL on the connection (issue 1248)
- fixed a bug where reconnections did not actually check for a working connection (issue 1251)

## sybase Driver Version 1.0.4

New Features and Bug Fixes

- implemented support for the prepared statement API
- implemented support for binding and retrieving "number" types
- implemented support for the following DBI options:
  - `"optimal-numbers"`: return `NUMERIC` or `DECIMAL` types as an integer if possible, if not as an arbitrary-precision number
  - `"string-numbers"`: return `NUMERIC` or `DECIMAL` types as strings (for backwards-compatibility)
  - `"numeric-numbers"`: return `NUMERIC` or `DECIMAL` types as arbitrary-precision number values
  - `"timezone"`: accepts a string argument that can be either a region name (ex: `"Europe/Prague"`) or a UTC offset (ex: `"+01:00"`) to set the server's time zone rules; this is useful if connecting to a database server in a different time zone. If this option is not set then the server's time zone is assumed to be the same as the client's time zone; see Time Zone Support.
- fixed auto-reconnect functionality (issue 131)
- removed trailing colon from error messages (issue 312)
- fixed returning decimal values; they were returned with too-high precision numbers which caused comparisons with the original number to fail (issue 512))
- implemented support for the following DBI options:
  - `"optimal-numbers"`: return numeric types as an integer if possible, if not as an arbitrary-precision number
  - `"string-numbers"`: return numeric types as strings (for backwards-compatibility)
  - `"numeric-numbers"`: return numeric types as arbitrary-precision number values
  - `"timezone"`: accepts a string argument that can be either a region name (ex: `"Europe/Prague"`) or a UTC offset (ex: `"+01:00"`) to set the server's time zone rules; this is useful if connecting to a database server in a different time zone. If this option is not set then the server's time zone is assumed to be the same as the client's time zone
- the default for the number options is now `"optimal-numbers"`, meaning that `NUMERIC` or `DECIMAL` values are retrieved as integers if possible, otherwise an arbitrary-precision number type is returned
- fixed `varchar` handling with freetds; freetds processes bind arguments differently than Sybase's ctlib and strings were sent with an extra space on the end that was stripped from the string when the value was returned from the DB (issue 563)
- fixed renaming duplicate columns according to the standard xxx_n format (issue 830)

## sybase Driver Version 1.0.3

New Features and Bug Fixes

- implemented support for specifying the hostname and port in the datasource in order to override the interfaces file