This article is part of a series that includes Firebird, Postgresql, Microsoft SQLServer, Oracle RDBMS, HSQLDB, MariaDB, MongoDB, and Excel. The goal is to set up a self-standing environment for testing an ODBC extension for gawk presented here to be completed. Excepting the present part which deals with the ODBC Driver manager’s installation which is a prerequisite, each part can be used independently from the others.
The test system is a debian v11 (bullseye).

Installation of the ODBC driver Manager

There are 2 main implementations of ODBC for Linux: UnixODBC (http://www.unixodbc.org/) and iODBC (http://www.iodbc.org); we picked the former for no particular reason.
The driver manager can be installed as root through the standard package management tool in Debian:

[email protected]:~# apt-get install libodbc1
[email protected]:~# apt install unixodbc 

[email protected]:~# odbcinst -j
unixODBC 2.3.6
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8

The system-wide file /etc/odbcinst.ini stores the list of installed ODBC drivers and is maintained by root. It is the default one, but its location can be changed and set in the environment variable $ODBCINST.
Let’s create a working folder in user debian’s home directory, our test account:

$ id
uid=1000(debian) gid=1000(debian) groups=1000(debian)
$ mkdir ~/odbc4gawk
$ export workdir=~/odbc4gawk
$ mkdir $workdir
$ cd $workdir

As most of the ODBC drivers have their shared libraries installed in /usr/lib/x86_64-linux-gnu/odbc, this path must be added the $LD_LIBRARY_PATH environment variable of any user that must use ODBC, preferably in the ~/.bashrc file (if bash is the select shell):

export LD_LIBRARY_PATH=/usr/lib/x86_64-linux-gnu/odbc:$LD_LIBRARY_PATH

We are now ready to install the ODBC drivers for each data source of interest.

Installation of the SQLite ODBC driver

SQLite along with its administrative tool isql are installed by the native package manager as root:

# apt install sqlite3
# apt install libsqliteodbc

Each time an ODBC driver is installed, it updates the file /etc/odbcinst.ini with driver-dependent information, which can later be checked using the above command odbcinst, e.g.:
List the installed ODBC drivers:

$ odbcinst -q -d
[SQLite3]

Query a particular driver:

$ odbcinst -q -d -n SQLite
SQLite3]
Description=SQLite3 ODBC Driver
Driver=libsqlite3odbc.so
Setup=libsqlite3odbc.so
UsageCount=1

As user debian, edit the file ~/.odbc.ini and add the SQLite data source’s details we will use:

$ cd $workdir 
$ mkdir sqlite
$ cd sqlite
$ vi ~/.odbc.ini
[mysqlitedb]
Description=My SQLite sample database
Driver=SQLite3
Database=/home/debian/odbc4gawk/sqlite/sampledb

Let’s check it:
List all the DSN currently defined in ~/.odbc.ini

$ odbcinst -q -s
[mysqlitedb]

List our new DSN:

$ odbcinst -q -s -n mysqlitedb
[mysqlitedb]
Description=My SQLite sample database
Driver=SQLite3
Database=/home/debian/odbc4gawk/sqlite/sampledb

which is the information we just entered above.

The ~/.odbc.ini file allows to hide a drivers’ private settings so that they don’t need to be specified later. When connecting to a data source, the name that is specified here between square brackets, the DSN, is enough. It is also possible to directly specify in-line all the parameters in this section when connecting programmatically but the code will need to be edited (and maybe recompiled) in case one them has to be changed, so using a DSN is preferable.
The default file location is the current user’s home directory but it can be changed and its full path name set in the environment variable $ODBCINI.

Let’s test the connection via ODBC using the command isql included with the ODBC driver manager:

$ isql mysqlitedb -v
+---------------------------------------+
| Connected!                            |
|                                       |
| sql-statement                         |
| help [tablename]                      |
| quit                                  |
|                                       |
+---------------------------------------+

The ODBC driver for SQLite does work.

To populate a database, start sqllite3:

$ /usr/bin/sqlite3
SQLite version 3.34.1 2021-01-20 14:10:07
Enter ".help" for usage hints.
Connected to a transient in-memory database.

Use “.open FILENAME” to reopen a persistent database.

sqlite> .open sampledb

The file sampledb has been created in the directory specified in ~/.odbc.ini.
Go to the following links, copy the SQL statements and paste them in sqllite3: table creation and insert data.

Still in sqlite3, check that the database has been populated by running the test SQL query listed above:

sqlite> SELECT
        c.country_name,
        c.country_id,
        l.country_id,
        l.street_address,
        l.city
FROM
        countries c
LEFT JOIN locations l ON l.country_id = c.country_id
WHERE
        c.country_id IN ('US', 'UK', 'CN');
Output:
China|CN|||
United Kingdom|UK|UK|8204 Arthur St|London
United Kingdom|UK|UK|Magdalen Centre, The Oxford Science Park|Oxford
United States of America|US|US|2014 Jabberwocky Rd|Southlake
United States of America|US|US|2011 Interiors Blvd|South San Francisco
United States of America|US|US|2004 Charade Rd|Seattle

Now, quit sqlite3 and re-run the same query from isql, the ODBC-based utility:

$ isql -v mysqlitedb
SQL> SELECT c.country_name, c.country_id, l.country_id, l.street_address, l.city FROM countries c LEFT JOIN locations l ON l.country_id = c.country_id WHERE c.country_id IN ('US', 'UK', 'CN')
+---------------------------+-------------+-----------+---------------------------------------------+----------------------+
| country_name              | country_id  | country_id| street_address                              | city                 |
+---------------------------+-------------+-----------+---------------------------------------------+----------------------+
| China                     | CN          |           |                                             |                      |
| United Kingdom            | UK          | UK        | 8204 Arthur St                              | London               |
| United Kingdom            | UK          | UK        | Magdalen Centre, The Oxford Science Park    | Oxford               |
| United States of America  | US          | US        | 2014 Jabberwocky Rd                         | Southlake            |
| United States of America  | US          | US        | 2011 Interiors Blvd                         | South San Francisco  |
| United States of America  | US          | US        | 2004 Charade Rd                             | Seattle              |
+---------------------------+-------------+-----------+---------------------------------------------+----------------------+
SQLRowCount returns 0
6 rows fetched

Note: the output has been shrunk a bit to reduce horizontal scrolling.

Everything looks good so far. Let’s now install the pyodbc ODBC module for python as root;

# apt install pip
# needed to compile pyodbc:
# apt install unixodbc-dev
# pip install pyodbc

As debian, execute the following python script with the following connection string:

import pyodbc 
cnxn = pyodbc.connect(DSN='mysqlitedb;UID=SA;PWD=admin2021!')
cursor = cnxn.cursor()  
cursor.execute("""SELECT
        c.country_name,
        c.country_id,
        l.country_id,
        l.street_address,
        l.city
FROM
        countries c
LEFT JOIN locations l ON l.country_id = c.country_id
WHERE
        c.country_id IN ('US', 'UK', 'CN')""")
row = cursor.fetchone() 
while row:
    print (row) 
    row = cursor.fetchone()
Output:
('China', 'CN', None, None, None)
('United Kingdom', 'UK', 'UK', '8204 Arthur St', 'London')
('United Kingdom', 'UK', 'UK', 'Magdalen Centre, The Oxford Science Park', 'Oxford')
('United States of America', 'US', 'US', '2014 Jabberwocky Rd', 'Southlake')
('United States of America', 'US', 'US', '2011 Interiors Blvd', 'South San Francisco')
('United States of America', 'US', 'US', '2004 Charade Rd', 'Seattle')Output:

Everything works as expected.
We have completed the steps to access an SQLite database via ODBC from isql and from the python module pyodbc. It was quite straightforward with that RDBMS. Once the gawk interface is completed, it should return the same output.
Turn now to the links below for the other data sources:
Firebird
HSQLDB
MariaDB
PostgreSQL
Oracle
Microsoft SQLServer for Linux
MongoDB
Excel


Thumbnail [60x60]
by
Cesare Cervini