0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Linux上のプログラムからODBCでDBMSに接続する

0
Last updated at Posted at 2025-01-26

はじめに

ここではLinux上のユーザープログラムが、同じくLinux上で稼働するDBMSにODBC経由で接続するための手順を示す。前提とするプラットフォームおよびDBMSは以下のとおり。

  • プラットフォームおよびDBMS
    PostgreSQL 17.2 (w/ unixODBC 2.3.9) + AlmaLinux 9.5
    PostgreSQL 17.5 (w/ unixODBC 2.3.12) + AlmaLinux 10.0
    MariaDB 11.4 (w/ unixODBC 2.3.9) + AlmaLinux 9.6
    MySQL 8.4 (w/ unixODBC 2.3.12) + AlmaLinux 10.0
  • ユーザープログラムが稼働するOS : DBMSと同じOS
  • ユーザープログラムを構成する技術 : gccで作成したネイティブアプリ

ユーザープログラムとDBMSの関係

ユーザープログラムは、何らかのConnectorを介してDBMSに接続する。DBMSごとに多種のConnectorが提供されており、ODBCはそのひとつであり、代表的なものとなる。
ODBC経由でDBMSに接続するには、DBMSの開発元から提供されているODBC Driverを予めクライアント側(ユーザープログラム側の環境)に組み込んでおく必要がある。また、ユーザープログラムは、ODBC Driver Managerを介してODBC Driverに接続する。
image.png
Windowsの場合、ODBC Driver Managerは、OSに組み込まれているため、その存在を特別意識しなくても良かったが、Linuxの場合、ODBC Driverと同様に、ODBC Driver Managerもクライアント側に組み込んでおく必要がある。
Linux用のODBC Driver Managerとしては、下記のものがよく知られている。

unixODBC

  • 概要: 最も一般的で広く使用されているオープンソースのODBC Driver Manager。
  • 特徴: 多くのODBC Driverやアプリケーションでサポートされている。
  • 利用シーン: 多くのLinuxディストリビューションにおける標準のODBC Driver Manager。
  • ライセンス: GNU General Public License (GPL) および GNU Lesser General Public License (LGPL)

iODBC (Independent Open DataBase Connectivity)

  • 概要: unixODBCと同様にオープンソースのODBC Driver Manager。最初にリリースされたODBC Driver Managerひとつで、クロスプラットフォーム対応を目指してる。
  • 特徴: macOSや他のUnix系システムでも広く使用されている。
  • 利用シーン: 特定の商用アプリケーションやiODBCに特化した環境で使われることがある。
  • ライセンス: BSD License

環境構築

ユーザープログラムがODBC経由でDBMSに接続するための環境構築手順を示す。DBMSのインストールについては、数多くの情報源があり、その設定方法も様々であるため、ここでは詳細を事細かに示すことはせず、最低限の記載にとどめる。また、ODBC Driver Managerについては、unixODBCを使用する。

PostgreSQL 17.2 (w/ unixODBC 2.3.9) + AlmaLinux 9.5

PostgreSQLの最低限の動作に必要な、下記のパッケージをダウンロードする。
postgresql17-libs-17.2-1PGDG.rhel9.x86_64.rpm
postgresql17-17.2-1PGDG.rhel9.x86_64.rpm
postgresql17-server-17.2-1PGDG.rhel9.x86_64.rpm
postgresql17-odbc-17.00.0004-1PGDG.rhel9.x86_64.rpm

上記は、PostgreSQLの公式サイトからダウンロード可能である。
https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-9-x86_64/

また、unixODBCは、RPMのダウンロードサイトからダウンロード可能である。
unixODBC-2.3.9-4.el9.x86_64.rpm
unixODBC-devel-2.3.9-4.el9.x86_64.rpm

ダウンロード後、下記のコマンドでインストールする。インストールする順番を間違えるとエラーとなる。

$ sudo rpm -ivh postgresql17-libs-17.2-1PGDG.rhel9.x86_64.rpm
$ sudo rpm -ivh postgresql17-17.2-1PGDG.rhel9.x86_64.rpm
$ sudo rpm -ivh postgresql17-server-17.2-1PGDG.rhel9.x86_64.rpm
$ sudo rpm -ivh unixODBC-2.3.9-4.el9.x86_64.rpm
$ sudo rpm -ivh unixODBC-devel-2.3.9-4.el9.x86_64.rpm
$ sudo rpm -ivh postgresql17-odbc-17.00.0004-1PGDG.rhel9.x86_64.rpm

PostgreSQLおよびunixODBCのインストール後、PostgreSQLおよびunixODBCの初期設定を行う。postgresユーザーでinitdbを実行する。コマンド実行時にpostgresユーザーのパスワードの設定を求められる。ここではパスワード=postgresとする。

$sudo su - postgres
$ /usr/pgsql-17/bin/initdb -E UTF8 --locale=C -A scram-sha-256 -W

postgresユーザーのまま、/var/lib/pgsql/17/data/pg_hba.confが下記のようになっていることを確認する。

local all all scram-sha-256
host all all 127.0.0.1/32 scram-sha-256
host all all ::1/128 scram-sha-256

同じく/var/lib/pgsql/17/data/postgresql.confを下記のように編集する。

listen_address='localhost'
port=5432

このあと、postgresユーザーをexitで抜けて下記を実行する。

$ sudo systemctl start postgresql-17.service
$ sudo systemctl enable postgresql-17.service

postgresユーザーとして、psqlでデータベース、テーブル、レコードを追加する。

$ psql -U postgres
# create database testdb;
# \l
... testdbを含むデータベース一覧が表示される ...
# \c testdb
# create table abc (id integer, name varchar(255));
# insert into abc values (0, 'hello');

上記で、\l はデータベース一覧を表示するコマンドで、\cはデータベースに接続するコマンドである。
postgresユーザーでのpsqlの実行後、psqlを抜けて、/etc/odbc.iniおよび/etc/odbcinst.iniを変更する。

# odbcinst.ini:
[PostgreSQL]
Driver=/usr/pgsql-17/lib/psqlodbcw.so
Setup=/usr/lib64/unixODBC/libodbcpsqlS.so
Driver64=/usr/pgsql-17/lib/psqlodbcw.so
Setup64=/usr/lib64/unixODBC/libodbcpsqlS.so
FileUsage=1

※/usr/lib64/unixODBC/libodbcpsqlS.soは、構成によっては存在しない場合があります。

# odbc.ini:
[PostgreSQL_DS]
Driver=PostgreSQL
Database=testdb
Servername=localhost
Port=5432
UserName=postgres
Password=postgres

下記isqlでtestdbに接続し、abcテーブルの情報を参照できることを確認する。

$ isql PostgreSQL_DS
SQL> select * from abc;

PostgreSQL 17.5 (w/ unixODBC 2.3.12) + AlmaLinux 10.0

PostgreSQLの最低限の動作に必要な、下記のパッケージをダウンロードする。
postgresql17-libs-17.5-3PGDG.rhel10.x86_64.rpm
postgresql17-17.5-3PGDG.rhel10.x86_64.rpm
postgresql17-server-17.5-3PGDG.rhel10.x86_64.rpm
postgresql17-odbc-17.00.0005-1PGDG.rhel10.x86_64.rpm

上記は、PostgreSQLの公式サイトからダウンロード可能である。
https://download.postgresql.org/pub/repos/yum/17/redhat/rhel-10-x86_64/

また、unixODBCは、RPMのダウンロードサイトからダウンロード可能である。
unixODBC-2.3.12-6.el10.x86_64.rpm
unixODBC-devel-2.3.12-6.el10.x86_64.rpm

ダウンロード後、下記のコマンドでインストールする。インストールする順番を間違えるとエラーとなる。

$ sudo rpm -ivh postgresql17-libs-17.5-3PGDG.rhel10.x86_64.rpm
$ sudo rpm -ivh postgresql17-17.5-3PGDG.rhel10.x86_64.rpm
$ sudo rpm -ivh postgresql17-server-17.5-3PGDG.rhel10.x86_64.rpm
$ sudo rpm -ivh unixODBC-2.3.12-6.el10.x86_64.rpm
$ sudo rpm -ivh unixODBC-devel-2.3.12-6.el10.x86_64.rpm
$ sudo rpm -ivh postgresql17-odbc-17.00.0005-1PGDG.rhel10.x86_64.rpm

以降の設定は、"PostgreSQL 17.2 (w/ unixODBC 2.3.9) + AlmaLinux 9.5"のセクションを参照のこと。

MariaDB 11.4 (w/ unixODBC 2.3.9) + AlmaLinux 9.6

MariaDBの最低限の動作に必要な、下記のパッケージをダウンロードする。
mariadb-11.4.5-rhel-9-x86_64-rpms.tar
mariadb-connector-odbc-3.2.4-rhel9-amd64.rpm
boost-program-options-1.75.0-10.el9.x86_64.rpm

上記は、MariaDBの公式サイト(以下)およびRPMのダウンロードサイトからダウンロード可能である。
https://dlm.mariadb.com/browse/mariadb_server/11.4.5/yum/rhel/
https://dlm.mariadb.com/browse/odbc_connector/3.2.4/

また、unixODBCは、RPMのダウンロードサイトからダウンロード可能である。
unixODBC-2.3.9-4.el9.x86_64.rpm
unixODBC-devel-2.3.9-4.el9.x86_64.rpm

ダウンロード後、tarを解凍し、下記のコマンドでインストールする。

$ sudo rpm -ivh MariaDB-shared-11.4.5-1.el9.x86_64.rpm MariaDB-common-11.4.5-1.el9.x86_64.rpm
$ sudo rpm -ivh MariaDB-client-11.4.5-1.el9.x86_64.rpm
$ sudo rpm -ivh boost-program-options-1.75.0-10.el9.x86_64.rpm
$ sudo rpm -ivh galera-4-26.4.21-1.el9.x86_64.rpm
$ sudo rpm -ivh MariaDB-server-11.4.5-1.el9.x86_64.rpm
$ sudo rpm -ivh unixODBC-2.3.9-4.el9.x86_64.rpm
$ sudo rpm -ivh unixODBC-devel-2.3.9-4.el9.x86_64.rpm
$ sudo rpm -ivh mariadb-connector-odbc-3.2.4-rhel9-amd64.rpm

インストールに際して下記の点に注意のこと。

  • インストールする順番を間違えるとエラーとなる。
  • 事前にPerl (cpanモジュール)をインストールする必要あり。
    $ cpan install File::Copy
    $ cpan install Sys::Hostname )

MariaDBおよびunixODBCのインストール後、MariaDBおよびunixODBCの初期設定を行う。

$sudo vi /etc/my.cnf.d/server.cnf
...
[mysqld]
character-set-server = utf8mb4
$ sudo vi /etc/my.cnf.d/client.cnf
...
[client]
default-character-set=utf8mb4

MariaDBのサービスを起動し、MariaDBの設定を行う。

$ sudo systemctl start mariadb
$ sudo systemctl enable mariadb
$ sudo mariadb-secure-installation

mariadb-secure-installationでは、クエリに対して、すべて空リターンで返答。rootユーザーのパスワードとして”root”を指定。
rootユーザーとしてmariadbコマンドを起動し、データベース、テーブル、レコードを追加する。

$ mariadb -u root -p
Enter password:
MariaDB [(none)]> create database testdb;
MariaDB [(none)]> show databases;
... testdbを含むデータベース一覧が表示される ...
MariaDB [(none)]> connect testdb;
MariaDB [(none)]> create table abc (id integer, name varchar(255));
MariaDB [(none)]> insert into abc values (0, ‘hello’);

rootユーザーで上記を実行後、mariadbコマンドを終了し、/etc/odbc.iniおよび/etc/odbcinst.iniを変更する。

# odbcinst.ini:
[MariaDB]
Driver=/usr/lib64/libmaodbc.so
DESCRIPTION=MariaDB ODBC Connector
Threading=0
UsageCount=1
# odbc.ini:
[MariaDB_DS]
Driver=MariaDB
Server=localhost
Uid=root
Pwd=root
Database=testdb

下記isqlでtestdbに接続し、abcテーブルの情報を参照できることを確認する。

$ isql MariaDB_DS
SQL> select * from abc;

MySQL 8.4 (w/ unixODBC 2.3.12) + AlmaLinux 10.0

MySQLの最低限の動作に必要な、下記のパッケージをダウンロードする。
mysql-8.4.6-1.el10.x86_64.rpm-bundle.tar
mysql-connector-odbc-9.4.0-1.el10.x86_64.rpm
mysql-connector-odbc-setup-9.4.0-1.el10.x86_64.rpm

上記は、MySQLの公式サイト(以下)からダウンロード可能である。
https://dev.mysql.com/downloads/mysql/
https://dev.mysql.com/downloads/connector/odbc/

また、unixODBCは、RPMのダウンロードサイトからダウンロード可能である。
unixODBC-2.3.12-6.el10.x86_64.rpm
unixODBC-devel-2.3.12-6.el10.x86_64.rpm

ダウンロード後、tarを解凍し、下記のコマンドでインストールする。

$ sudo rpm -ivh mysql-community-common-8.4.6-1.el10.x86_64.rpm mysql-community-client-plugins-8.4.6-1.el10.x86_64.rpm mysql-community-libs-8.4.6-1.el10.x86_64.rpm mysql-community-client-8.4.6-1.el10.x86_64.rpm mysql-community-icu-8.4.6-1.el10.x86_64.rpm
mysql-community-server-8.4.6-1.el10.x86_64.rpm
$ sudo rpm -ivh unixODBC-2.3.12-6.el10.x86-64.rpm
$ sudo rpm -ivh unixODBC-devel-2.3.12-6.el10.x86-64.rpm
$ sudo rpm -ivh mysql-connector-odbc-9.4.0-1.el10.x86-64.rpm
$ sudo rpm -ivh mysql-connector-odbc-setup-9.4.0-1.el10.x86-64.rpm

MySQLのインストール後、下記のコマンドでMySQLのサービスを起動する。

$ sudo systemctl start mysqld
$ sudo systemctl enable mysqld

起動時に一時パスワードの設定されたrootユーザーが作成される。一時パスワードは下記で取得可能。

$ grep 'temporary password' /var/log/mysqld.log

rootユーザーでmysql(SQLシェル)を起動し、パスワードを変更する。パスワードを変更しないと、mysqlでのコマンド実行が拒絶される。

$ mysql -uroot -p
mysql> ALTER USER 'root'@'localhost' IDENTIFIED BY '<new password>';

データベース、テーブル、レコードを追加する。

$ mysql -uroot -p
mysql> create database testdb;
mysql> connect testdb;
mysql> create table abc (id integer, name varchar(255));
mysql> insert into abc values (0, ‘hello’);

rootユーザーで上記を実行後、mysqlコマンドを終了し、/etc/odbc.iniおよび/etc/odbcinst.iniを変更する。

# odbcinst.ini:
[MySQL ODBC 9.4 Unicode Driver]
DRIVER=/usr/lib64/libmyodbc9w.so
SETUP=/usr/lib64/libmyodbc9S.so
UsageCount=1
# odbc.ini:
[MySQL_DS]
Driver=MySQL ODBC 9.4 Unicode Driver
Server=localhost
USER=root
PASSWORD=xxxx
Database=testdb

下記isqlでtestdbに接続し、abcテーブルの情報を参照できることを確認する。

$ isql MySQL_DS
SQL> select * from abc;

ユーザープログラム

下記のプログラムは、DBMSに接続し、切断するだけのサンプルコードである。下記でコンパイルおよび実行することができる。

$ gcc testdb.cpp -lodbc -lodbcinst -o testdb
$ ./testdb
#include <cstdlib>
#include <cstdio>
#include <sql.h>
#include <sqlext.h>

SQLHENV  henv;
SQLHDBC  hdbc;
SQLHSTMT hstmt;

// Return 0: Success, -1:Error
int open_database(SQLCHAR* connect_str, SQLCHAR statemsg[10], SQLCHAR msg[1024])
{
	SQLINTEGER native; // This will not be refered from anywhere
	SQLSMALLINT actual_msg_len; // This will not be refered from anywhere

	// Alloc environment handle
	if (SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv) == SQL_ERROR) {
		if (henv != SQL_NULL_HENV) {
			SQLGetDiagRec(SQL_HANDLE_ENV, henv, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		}
		return -1;
	}
	SQLSetEnvAttr(henv, SQL_ATTR_ODBC_VERSION, reinterpret_cast<SQLPOINTER>(SQL_OV_ODBC3), 0);

	// Alloc DB connection handle
	if (SQLAllocHandle(SQL_HANDLE_DBC, henv, &hdbc) == SQL_ERROR) {
		SQLGetDiagRec(SQL_HANDLE_ENV, henv, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	// SQLDriverConnect
	SQLCHAR conn_out[255]; // This will not be refered from anywhere
	SQLSMALLINT conn_out_len; // This will not be refered from anywhere
	SQLRETURN Ret = SQLDriverConnect(hdbc, NULL, connect_str, SQL_NTS, conn_out, 255, &conn_out_len, SQL_DRIVER_COMPLETE);
	if (Ret == SQL_ERROR || Ret == SQL_SUCCESS_WITH_INFO) {
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	// Alloc statement handle 
	if (SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt) == SQL_ERROR) {
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	return 0;
}

// Return 0: Success, -1:Error
int close_database(SQLCHAR statemsg[10], SQLCHAR msg[1024])
{
	SQLINTEGER native; // This will not be refered from anywhere
	SQLSMALLINT actual_msg_len; // This will not be refered from anywhere

	// Free statement handle
	if (SQLFreeHandle(SQL_HANDLE_STMT, hstmt) == SQL_ERROR) {
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	// SQLDisconnect
	SQLRETURN Ret = SQLDisconnect(hdbc);
	if (Ret == SQL_ERROR || Ret == SQL_SUCCESS_WITH_INFO) {
		SQLGetDiagRec(SQL_HANDLE_DBC, hdbc, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	// Free DB connection handle
	if (SQLFreeHandle(SQL_HANDLE_DBC, hdbc) == SQL_ERROR) {
		SQLGetDiagRec(SQL_HANDLE_ENV, henv, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	// Free environment handle
	if (SQLFreeHandle(SQL_HANDLE_ENV, henv) == SQL_ERROR) {
		SQLGetDiagRec(SQL_HANDLE_ENV, henv, 1, statemsg, &native, msg, 1024, &actual_msg_len);
		return -1;
	}

	return 0;
}

int main(int argc, char* argv[])
{
	SQLCHAR statemsg[10];
	SQLCHAR msg[1024];
	SQLCHAR connect_str[64] = "DSN=PostgreSQL_DS;";
	if (open_database(connect_str, statemsg, msg) == -1) {
		printf("statemsg=%s, msg=%s\n", (char*)statemsg, (char*)msg);
		return -1;
	}
	if (close_database(statemsg, msg) == -1) {
		printf("statemsg=%s, msg=%s\n", (char*)statemsg, (char*)msg);
		return -1;
	}
	printf("success!\n");
	return 0;
}

接続文字列の指定では、前述PostgreSQLに対するisqlの実行と同様にodbc.iniで設定したデータソース名'PostgreSQL_DS'を指定しているが、odbc.iniおよびodbcinst.iniに記載した個別設定をconnet_strに指定することもできる。

SQLCHAR connect_str[128] = "Driver=/usr/pgsql-17/lib/psqlodbcw.so;Server=127.0.0.1;Database=testdb;UID=postgres;PWD=postgres;Port=5432;";
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?