C++とSQLite3

概要

SQLite を利用することは、エディタ用のマクロにはあまりないことかもしれませんが、
ここでは sqlite_modern_cpp を使用して SQLite3を操作する例を示します

準備

SQLite3ツール郡

SQLite3を使えるようにフォルダに以下のようなファイル群を配置。

PICTURE

SQLite Download Pageの中央部の「Precompiled Binaries for Windows」に含まれています。
注意点としては、sqlite3.dll は秀丸の本体のビット数と一致させてください。
「sqlite3.dll」さえあればプログラムからの操作はできますが、
一般的には、テーブル内容の確認等をするため、上図のようにツール群と一緒に運用することになるはずです。

sqlite3.dll

PICTURE

コンパイルするためには、sqlite3.h と sqlite3.c が必要となります。
SQLite Download Pageの一番上部の「Source Code」に含まれています。

sqlite_modern_cpp

sqlite_modern_cpp のヘッダ群が必要です。

C++とSQLite3

  • C++側のソース

    TestSqlite.dllとしてコンパイル
    #include <windows.h>
    #include <string>
    
    #include <iostream>
    #include <sstream>
    #include "sqlite_modern_cpp.h"
    
    #include "HmCppInvoke.h"
    
    using namespace Hidemaru;
    
    using namespace  sqlite;
    using namespace std;
    
    
    int testSqlLite3() {
    
        try {
    
            // 現在実行する.macファイルと同じ位置に dbfile.db を生成する。
            wstring currentmacrodirectory = Hm.Macro.getVar<wstring>(L"currentmacrodirectory");
            string u8_currentmacrodirectory = Text::Encoding::utf16_to_utf8(currentmacrodirectory);
    
            // データベースファイル「dbfile.db」が存在しない場合は作成します。
            database db(u8_currentmacrodirectory + "/dbfile.db");
    
            // クエリを実行し、'user' テーブルを作成します
            db <<
                "create table if not exists user ("
                "   _id integer primary key autoincrement not null,"
                "   age int,"
                "   name text,"
                "   weight real"
                ");";
    
            // 新しいユーザーレコードを挿入します。
            // フィールドを「?」にバインドします。
            // バインディングに許可されているタイプは次のとおりであることに注意してください:
            //      int ,long, long long, float, double
            //      string , u16string
            // sqlite3はutf8およびutf16文字列のみをサポートします。utf8にはstd::stringを使用し、utf16にはstd::u16stringを使用する必要があります。
            // u"mytext" は char16_t* 型の utf16文字列リテラル であることに注意してください。
            db << "insert into user (age,name,weight) values (?,?,?);"
                << 20
                << u"bob"
                << 83.25;
    
            int age = 21;
            float weight = 68.5;
            string name = "jack";
            db << u"insert into user (age,name,weight) values (?,?,?);" // utf16 query string
                << age
                << name
                << weight;
    
            std::stringstream ss;
            ss << "The new record got assigned id " << db.last_insert_rowid() << "\r\n";
            Hm.OutputPane.output(Text::Encoding::utf8_to_utf16(ss.str()));
    
            // slects from user table on a condition ( age > 18 ) and executes
            // the lambda for each row returned .
            db << "select age,name,weight from user where age > ? ;"
                << 18
                >> [&](int age, string name, double weight) {
                cout << age << ' ' << name << ' ' << weight << "\r\n";
            };
    
            // selects the count(*) from user table
            // 単一のculumn単一行の結果は、int、long、long、float、double、string、u16stringにのみ抽出できることに注意してください
            int count = 0;
            db << "select count(*) from user" >> count;
            ss.clear();
            ss << "cout : " << count << endl;
            Hm.OutputPane.output(Text::Encoding::utf8_to_utf16(ss.str()));
    
            // 複数の列行を抽出することもできます
            db << "select age, name from user where _id=1;" >> tie(age, name);
            ss.clear();
            ss << "Age = " << age << ", name = " << name << "\r\n";
            Hm.OutputPane.output(Text::Encoding::utf8_to_utf16(ss.str()));
    
            // これも機能し、戻り値は自動的に文字列に変換されます
            string str_count;
            db << "select count(*) from user" >> str_count;
            ss.clear();
            ss << "scount : " << str_count << "\r\n";
            Hm.OutputPane.output(Text::Encoding::utf8_to_utf16(ss.str()));
    
            wstringstream wss;
            wss << "abc" << L"abc";
        }
        catch (exception& e) {
            throw;
        }
    }
    
    extern "C" __declspec(dllexport) THmNumber test() {
        Hm.funcDllExport();
    
        try {
            testSqlLite3();
        }
        catch (std::exception& e) {
            // エラー内容をchar → wstring へ
            auto wide_what = Text::Encoding::utf8_to_utf16( e.what() );
            Hm.OutputPane.output(wide_what + L"\r\n");
        }
    
        return 1;
    }
    
  • 秀丸マクロ側のソース

    test.mac
    // TestSqlite.dllとしてコンパイルした
    #dll = loaddll(currentmacrodirectory + @"\TestSqlite.dll");
     
    // 途中でマクロの文法や型の致命的エラーが発生した場合でもdllを解放する。
    if (version >= 898) { eval "keepdll #dll, 0"; }
     
    #r = dllfuncw(#dll, "test");
     
    freedll(#dll);