スポンサーリンク

libpqxxとC++でPostgreSQLにアクセスする ~C++からSQLを実行する~

記事内に広告が含まれています。

以前、「libpqxxを使うためにインストールしたよ~」みたいな記事を書いたことがありました。次の2つの記事です。

で、この2つの記事ではPostgreSQL(PostgreSQLって実は結構打ちにくいんで、これからは単にPostgresと表現します)とlibpqxxをMSYS2環境でビルドしただけでした。どんなソースコードを書けばいいのかみたいな解説は一切なかったので、ここでざっくりと解説しとこうかと。

ちなみに、Postgresってのは、データベース管理システムの一種で、こいつにSQL文を与えればデータベースを色々といじることが出来ます。複数の表を結合したり、ある条件に当てはまるデータだけを抜き出してきたりなんてことも出来るようになっています。

そのSQL文はコマンドプロンプトとか、Postgres付属のソフトウェアを使って送信することが出来るのですが、C++なんかのプログラミング言語から送信したい場合もあります。そういうときには、C++からPostgresにSQL文を与えるためのインターフェイスが必要になります。

コマンドプロンプトとか、Postgres付属のソフトウェアは、人間が使うように作られたインターフェイスで、そのインターフェイスを使うことでPostgresにSQL文を送信できるわけです。それと同じように、C++の場合にもC++用に作られたインターフェイスを使ってSQL文を送信しないといけません。

そのC++用のインターフェイスがlibpqxxになります。libpqxxに用意されている関数を利用してPostgresに色んなSQL文を送信します。

スポンサーリンク

Postgresはサーバーとクライアントで成り立つ

まず、Postgresの基本的な構造を説明しておきます。ここが理解できていないと、そもそもlibpqxxを使う環境すら整わないんで。

Postgresはクライアント/サーバーモデルと呼ばれる構造になっています。もし、この段階で「あぁ、クライアント/サーバーモデルなのね」と理解出来た方は次の節に進んでいいただいても問題ありません。分からなかった方は、今から説明していきますんで、本題までもうしばらく辛抱いただきましょう。

その名が示す通り、Postgresはクライアントプロセスとサーバプロセスという2つの役割が相互作用することで動作しています。その2つはPostgresのマニュアル1.2節で次のように説明されています。以下の引用は、上2つが英語版の公式資料、下二つが日本語版になります。

A server process, which manages the database files, accepts connections to the database from client applications, and performs database actions on behalf of the clients. The database server program is called postgres.

英語版マニュアルより

The user’s client (frontend) application that wants to perform database operations. Client applications can be very diverse in nature: a client could be a text-oriented tool, a graphical application, a web server that accesses the database to display web pages, or a specialized database maintenance tool. Some client applications are supplied with the PostgreSQL distribution; most are developed by users.

英語版マニュアルより

サーバプロセス。 これは、 データベースファイルを管理し、 クライアントアプリケーションからのデータベースの接続を受け付け、 クライアントに代わってデータベースに対する処理を行います。 データベースサーバプログラムはpostgresと呼ばれています。

日本語版マニュアルより

ユーザの、 データベース操作を行うクライアント(フロントエンド)アプリケーション。 クライアントアプリケーションはその性質上非常に多様性があります。 テキスト指向のツール、 グラフィカルなアプリケーション、 データベースにアクセスしWebページを表示するWebサーバ、 あるいはデータベースに特化した保守ツールなどがあります。 いくつかのクライアントアプリケーションがPostgreSQLの配布物に同梱されていますが、 ほとんどのクライアントアプリケーションはユーザによって開発されます。

日本語版マニュアルより

Postgresは日本語版資料も充実しているんで、そちらも参考にしていただければと思います。

上の引用をまとめると要するに、サーバプロセスは門番みたいな役割を果たしてるってわけですな。僕らがデータベースを使う場合はその門番たるサーバプロセスに処理を代行してもらわないといけないんだと。

その門番に処理の代行をお願いするのがクライアントアプリで、その目的によって色んな種類があるってことですな。その目的に応じて、ユーザはクライアントアプリを利用すると。もしPostgresに同梱されているクライアントアプリの中に、目的に適ったものが無ければ自分で作ってもいいよと。

ここまでの話で、サーバプロセス(Postgres)とクライアントアプリという2つのプロセスを走らせておかないとPostgresを利用できないということが理解できたかと思います。

ここで言う”サーバプログラム”も”クライアントアプリ”も単にプログラムと考えていただければ分かりやすいかと思います。要するに、Postgresを使うときはプログラムを2つ動かさないとダメだよと。

この内、僕らがC++で作ろうとしているのはクライアントアプリ側になります。つまり、データベースの門番にあれこれとお願いするプログラムを作るわけになります。で、そのお願いをするときにlibpqxxが必要になるってことですな。

なので、もしlibpqxxを使ったプログラムを走らせて「上手く動作しない。バグかな?」と思ったときは、一応まずはサーバプロセスが動作しているかどうかを確認してくださいませ~。

ソースコード

この記事の最後に挙げておいたおすすめ本を読みながら、以前”shop”なるデータベースを作ったことがあったので、今回はそのデータベースに新しいテーブルを作るプログラムを作ってみました。ほとんど公式にあったプログラムのコピーですが。で、そのプログラムが以下になります。

毎度のことですが、このプログラムを実行して問題が発生したとしても責任は負いませんので、実行は自己責任でお願いします。特に、データベースSQLの場合、データの読み込み中には新しいデータの書き込みが出来なくなる場合があるので、データベースに詳しくない状態で、実務でいきなりこのソースコードを実行するのは避けていただいた方が無難かと思います。

/********************************
*
* lipqxxを使って、PostgreSQLのサーバーにSQL文を送信してみる
*
*********************************/
#include <iostream>
#include <libpq-fe.h>
#include <pqxx/pqxx>

int main()
{
  try
  {
    pqxx::connection C{"postgresql:///shop?host=localhost&port=/*ポート名*/&user=/*ユーザ名*/"};
    std::cout << "Connected to " << C.dbname() << std::endl;
    pqxx::work W(C);

    pqxx::result R = W.exec("CREATE TABLE sales_details(Registration_date DATE, Product_id CHAR(4) NOT NULL, Quantity INTEGER, PRIMARY KEY (Registration_date));");

    std::cout << "Making changes definite: ";
    W.commit();
    std::cout << "OK." << std::endl;
  }
  catch (const std::exception &e)
  {
    std::cerr << e.what() << std::endl;
    return 1;
  }
  
  return 0;
}

ソースコードの解説

このソースコードでは、Postgresの中にshopという名前のデータベースがあることが前提になっています。もしそのテーブルに接続できなかった場合はエラーになりますのでご注意ください。

上記の14行目

pqxx::connection C{"postgresql:///shop?host=localhost&port=/*ポート名*/&user=/*ユーザ名*/"};

で、接続先とか接続するときのオプションなんかを指定しています。ポート番号はデフォルトなら5432で、ユーザ名はpostgresになっています。

その後、18行目

pqxx::result R = W.exec("CREATE TABLE sales_details(Registration_date DATE, Product_id CHAR(4) NOT NULL, Quantity INTEGER, PRIMARY KEY (Registration_date));");

でSQL文を実行しています。今回はCREATE TABLEで新しいテーブルを作るというSQLを実行しています。

続く20-22行目で、トランザクションがコミットされたかどうかを表示しています。もし、コミットされなかったらW.commit()の次はエラー処理に移るので、OKは表示されません。

std::cout << "Making changes definite: ";
W.commit();
std::cout << "OK." << std::endl;

以上を実行すると、僕の環境では次のようになりました。

Connected to shop
Making changes definite: OK.

そして、コマンドプロンプトからpsqlを起動して\dコマンドでテーブルをすべて表示してみると

             List of relations
 Schema |     Name      | Type  |  Owner
--------+---------------+-------+----------
 public | product       | table | postgres
 public | sales_details | table | postgres
(2 rows)

となっていました。新しくsales_detailsというテーブルが作られていました。というわけで、見事、libpqxxを使ってC++からSQLを送信することに成功しました。

皆様も色んなアイデアで遊んでいってくださいませ~。ではでは~。

P.S. もし、SQLを通してPostgresの使い方を勉強したいという学習意欲が高めの方にはこちらの本をおすすめしておきます。

比較的理解しやすいSQL文から順に解説されているので、結構分かりやすいなと思いました。とりあえず、この本を1冊だけ抑えておけば十分なんじゃないかと。

まぁその分、各SQL文の必要性とか使い所が分からなくなってだれちゃうかもしれませんが、そうなったらこの記事みたいに色々と自分でいじってみると良いかもしれません。もしくは、併せてこちらの本を読んでみるとかですかね。

こちらは、データベースに記録されているデータに対して、どんな分析をどんなSQL文で実現するかって観点で書かれていまして、なかなか分かりやすい1冊でした。

ただ、データが既に存在することを前提としていたり、SQLそのものを解説しているわけではなかったりで、あくまでも勉強したSQL文を実務でどう使えばいいのかを知りたい人向けではありますが。

タイトルとURLをコピーしました