Using SQLite with ODBC, I have two options on how to chose a database file:
- I can define a DSN in a configuration file, and hardcode the file there; this way I can use odbc_connect/3.
- I can not bother with a configuration file and use odbc_driver_connect/3, then I can choose the database file from the Prolog source.
How are others doing this? I almost feel like for SQLite, using odbc_driver_connect/3 is the correct approach, despite the advice from the docs which says,
Whenever possible, applications should use odbc_connect/3.
(Figuring out all of this took a while so I will just share it here. It belongs to a Wiki maybe but I’d like someone with more experience to comment on this first)
First, my OS and hardware: MacOS Ventura 13.2.1 on Intel
I have installed SWI-Prolog using the Mac OS X disk image with relocatable application bundle. I see:
$ swipl --version
SWI-Prolog version 9.1.7 for fat-darwin
Then, I used homebrew to install sqliteodbc (which has sqlite and unixodbc as dependencies):
$ brew update && brew install sqlite unixodbc sqliteodbc
Now it gets interesting. After banging my head against the wall for a while, I ran:
$ odbcinst -j
unixODBC 2.3.11
DRIVERS............: /usr/local/etc/odbcinst.ini
SYSTEM DATA SOURCES: /usr/local/etc/odbc.ini
FILE DATA SOURCES..: /usr/local/etc/ODBCDataSources
USER DATA SOURCES..: /Users/xxx/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
Before that, following the docs from sqliteodbc, I used /etc/odbcinst.ini instead of /usr/local/etc/odbcinst.ini. Annoyingly, isql doesn’t care which of the two files has the configuration in it, so running
$ isql -v testdsn
… happily works, no matter in which of the two files you put the driver config. ![]()
And of course make sure you put the correct path for the driver, some docs might be missing the “3” there in the middle:
$ cat odbcinst.ini
[SQLite3]
Description = SQLite3 ODBC Driver
Driver = /usr/local/lib/libsqlite3odbc.so
Setup = /usr/local/lib/libsqlite3odbc.so
Threading = 2
If someone knows if the “Threading=2” is necessary and what it means, please share. It was in the sqliteodbc README.
Then comes your personal “USER DATA SOURCES” file in ~/.odbc.ini. You might read the sqliteodbc README; and even man odbc.ini on your system and they might tell you that: “[ODBC Data Sources]” is a mandatory section; this is not true for my case at least.
Even worse, the man page for odbc.ini claims:
Each data source is identified by a [section header], which is the DSN name used by applications. Each DSN definition section may contain values for the keys:
• Driver (REQUIRED)
The name of the ODBC driver to use for the DSN. The name must exactly match the
[section name] of the driver definition stored in odbcinst.ini (and listed by
odbcinst -q -d).
This is a dirty rotten lie. In fact, if I do that and try to use odbc_connect/3, I see:
ERROR: ODBC: State IM002: [unixODBC][Driver Manager]Data source name not found and no default driver specified
Instead, I must put the full path to the driver installed by sqliteodbc, so:
$ cat ~/.odbc.ini
[testdsn]
Description = Test DSN
Driver = /usr/local/lib/libsqlite3odbc.so
Database = <full path to the database file>
Now I can do:
?- odbc_connect(testdsn, X, []), odbc_disconnect(X).
X = '$odbc_connection'(105553118773888).
I can also skip the Database line from ~/.odbc.ini completely, it still “works”, with a transient in-memory database I assume. I didn’t figure out how to save the state to a file.
The other option is to use odbc_driver_connect/3 and explicitly list the driver and the database. This works even if the configurations files are empty (or wrong):
?- odbc_driver_connect('Driver=/usr/local/lib/libsqlite3odbc.so;Database=<full path to database file>;', X, []),
odbc_disconnect(X).
X = '$odbc_connection'(105553167451472)
… but still wondering how to choose the database file other than defining multiple DSNs.