Skip to content

Releases: xo/odbc

Release list

v0.1.1

Choose a tag to compare

@kenshaw kenshaw released this 07 Oct 08:29

This release fixes one bug and documents a crash that is not a fault of odbc.

Fixed

A statement that returns no result set, such as CREATE TABLE, sent through QueryContext, failed on the first Next with fetching: return code -1 with no diagnostic. The driver fetched from a statement that has no result. It now returns no rows, and Err and Close report no error. A client that sends every statement through QueryContext, as usql can, met this. TestQueryWithoutResult covers all six tested databases.

Documented

  • The README has a FAQ entry for a crash of a program that links both go-sqlite3 and the DuckDB bindings and uses the SQLite ODBC driver. The DuckDB bindings link with -rdynamic, so the program exports the sqlite3_* functions of go-sqlite3, and the SQLite ODBC driver binds to them while it also uses the SQLite of the system. The first query then faults. Build go-sqlite3 with the tag libsqlite3, leave one of the two libraries out, or build with CGO_ENABLED=0. odbc cannot prevent it.
  • The SQLite ODBC driver answers a VALUES statement with SQL_NO_DATA, so the driver manager refuses to describe its columns with HY010. select * from (values (1)) works. The backlog records it as a known limit.

Everything else in v0.1.0 is unchanged, and CI passed on all three systems for this release.

v0.1.0

Choose a tag to compare

@kenshaw kenshaw released this 07 Oct 02:34

This is the first release of odbc, a database/sql driver for ODBC written in pure Go. It loads the ODBC driver manager of the system at run time with purego. It needs no cgo and no C compiler. One code base serves Linux, macOS and Windows.

Install

go get github.com/xo/odbc@v0.1.0

You need an ODBC driver manager and the ODBC driver of your database on the machine. The README explains the data source name and has an FAQ.

What it does

  • It connects with a URL such as odbc+PostgreSQL+Unicode://user:pass@host/db, or with an ODBC connection string.
  • It supports prepared and direct statements, bound parameters, transactions with isolation levels, and cancellation through the context.
  • Values have the Go types of the dbimp kinds. A decimal is a *apd.Decimal, a date is a dbimp.Date, and a timestamp with no zone is a dbimp.LocalDateTime.
  • It finds the size of SQLWCHAR when it loads the driver manager, so UTF-16 and UTF-32 managers both work.
  • Statements take the same options as the other dbimp drivers: WithTimeout, WithDatabase, WithReadonly, WithParameter, WithMaxRows, WithNoScan and WithFetchSize. An option that a database driver cannot honor fails with dbimp.ErrNotSupported.
  • WithFetchSize reads rows in blocks. It was two to four times faster in the tests, and it never returns a value that was cut short.
  • A program can ask the driver about the database: odbc.Drivers, odbc.DataSources, odbc.Conn with GetInfo*, Tables, Columns and PrimaryKeys, Config.OnWarning, Config.TraceFile, and error classes such as odbc.ErrIntegrity.

What is tested

The tests run the dbmeta fixtures and queries and a round trip of each kind of value. CI runs them on every push and every night.

System Databases
Linux PostgreSQL, MariaDB, MySQL, SQL Server, SQLite, DuckDB
macOS PostgreSQL, MariaDB, SQLite, DuckDB
Windows PostgreSQL, MySQL, SQLite, DuckDB

MariaDB Connector/ODBC serves both MariaDB and MySQL. SQL Server is tested on Linux only.

Known limits

  • WithReadonly(true) always fails with dbimp.ErrNotSupported, because three of the six databases accept the ODBC read only mode and still write.
  • PostgreSQL timestamptz loses its zone, because psqlODBC reports it as a timestamp with no zone.
  • Non-ASCII text in an SQL literal is wrong with the SQLite ODBC driver on macOS and in a container with no locale. An argument is fine.
  • iODBC works, but the database drivers of Homebrew are built for unixODBC and read its text wrongly.
  • MariaDB Connector/ODBC before 3.2 lists no primary key of a MySQL 8 table.

The decisions behind all of this are in docs/decisions/, and docs/BACKLOG.md lists the work that is left.