Fork me on GitHub

2011/11/16


このエントリーをはてなブックマークに追加
最近バージョン1リリースを目標にガチャガチャと凄い勢いでパッケージ構成が見直されていますが、その中でGo言語向けに新しいパッケージが入りました。
これまででもsqlite3やmysql向けに何人もの人が個性的なドライバを書き、インタフェースも揃わず、中には開発をやめ、それを使ったアプリケーションの開発も止まるという悪循環になろうとしていました。
そんな中入ったのがexp/sqlです。expなのでまだ実験段階なのですが、Go言語としてはデータベースの枠組みだけ提供し、ドライバはサードパーティに作ってもらうというもくろみです。これによりデータベースに関してはドライバを構成通りに開発すれば使用者側は同じインタフェースで呼び出せるという物です。PerlでいうDBIですね。

誰もあまり手を付けてなさそうだったので、3本ばかしドライバを書かせて頂きました。

SQLite3

mattn/go-sqlite3 - GitHub

sqlite3 driver for go that using exp/sql

https://github.com/mattn/go-sqlite3
ご存知、みんな大好きSQLite3ですね。golang-gonutsに放流した時にはなかなか反響がよろしくて良かったです。
ちなみにこれを使ってデータベースを扱うコードを書くと、こんな感じになります。
package main

import (
    "exp/sql"
    "fmt"
    _ "github.com/mattn/go-sqlite3"
    "os"
)

func main() {
    os.Remove("./foo.db")

    db, err := sql.Open("sqlite3""./foo.db")
    if err != nil {
        fmt.Println(err)
        return
    }

    sqls := []string{
        "create table foo (id integer not null primary key, name text)",
        "delete from foo",
    }
    for _, sql := range sqls {
        _, err = db.Exec(sql)
        if err != nil {
            fmt.Printf("%q: %s\n", err, sql)
            return
        }
    }

    tx, err := db.Begin()
    if err != nil {
        fmt.Println(err)
        return
    }
    stmt, err := tx.Prepare("insert into foo(id, name) values(?, ?)")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer stmt.Close()

    for i := 0; i < 100; i++ {
        _, err = stmt.Exec(i, fmt.Sprintf("こんにちわ世界%03d", i))
        if err != nil {
            fmt.Println(err)
            return
        }
    }
    tx.Commit()

    rows, err := db.Query("select id, name from foo")
    if err != nil {
        fmt.Println(err)
        return
    }
    defer rows.Close()

    for rows.Next() {
        var id int
        var name string
        rows.Scan(&id, &name)
        println(id, name)
    }
}

Microsoft ActiveX Object DataBase

mattn/go-adodb - GitHub

Microsoft ActiveX Object DataBase driver for go that using exp/sql

https://github.com/mattn/go-adodb
まだまだCOMは死んでない。いまだに使われてるADODBをCGOを使わずに実装したgo-oleを使い、データベース操作出来る様にしました。
mattn/go-ole - GitHub

win32 ole implementation for golang

https://github.com/mattn/go-ole
ちなみにこれを使うと、AccessのMDBファイルを弄れたりCSVファイルにSQLを流せたり出来ます。便利!
こちらについては1人だけでしたが「Cool!」を頂きました。良かったですね。そうですね。

Yahoo! Query Language

mattn/go-yql - GitHub

YQL database driver for golang.

https://github.com/mattn/go-yql
これを使うとSQLでRSSがセレクト出来たりして嬉しいのですが...
package main

import (
    "exp/sql"
    "fmt"
    _ "github.com/mattn/go-yql"
)

func main() {
    db, _ := sql.Open("yql""")

    stmt, err := db.Query(
        "select * from rss where url = ?",
        "http://blog.golang.org/feeds/posts/default?alt=rss")
    if err != nil {
        fmt.Println(err)
        return
    }
    for stmt.Next() {
        var data map[string]interface{}
        stmt.Scan(&data)
        fmt.Printf("%v\n", data["link"])
        fmt.Printf("  %v\n\n", data["title"])
    }
}
いかんせん、Googleプロダクトの言語なので、「YQLドライバ作ったよ!」なんて言えずにおそらくお蔵入りするかと思います。

追記
ちなみに僕の思惑では、おそらく今後Google App EngineはRDBMSを採用する事になって(有料かもね)、そのエンジン構成としてこれを使わせるんじゃないかなと思っています。例えばappspotではGoogleが提供する(中身は何かは知らない)RDBMSで、ローカルの開発環境向けにはSQLiteみたいな...。
Posted at 21:09 in ソフトウェア::lang::go
Tagged as: ado, adodb, golang, sqlite, yql
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2011/09/26


このエントリーをはてなブックマークに追加

※ネタです

※UDFです

Vimテクニックバイブル ~作業効率をカイゼンする150の技 Vimテクニックバイブル ~作業効率をカイゼンする150の技
Vimサポーターズ
技術評論社 / ¥ 3,129 (2011-09-23)
 
発送可能時間:在庫あり。


正誤表を書くのにしばらくこの本をちょっと眺めてみたら、SQLiteのUDFって簡単に作れるんだなー、と思った && そういやV8ってライブラリとして簡単にリンクできるはずだな、と思い出した ので、ついカッとなって作った。

sqlite3udf-jseval - GitHub

http://github.com/mattn/sqlite3udf-jseval

UDFうんぬn

ほとんど↑の本、全然関係ないと思ってたけど、やっぱりSQLiteのUDFについて全然書いてなかった。しょうがないので軽く紹介しておくと

UDFを追加する場合、SQLiteの再コンパイルは必要ない (しかるべき所に.soがおいてあればいい)
UDFはこの辺読んどけばだいたい分かる。

例えば文字列っぽいものを返すmyfuncっていうUDFを作りたい場合
SQLITE_EXTENSION_INIT1 static void js_eval_func(sqlite3_context *context, int argc, sqlite3_value **argv);
int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api);
の二つの関数を実装したmyfunc.cっていうコードを用意してあげて
gcc -o myfunc.so myfunc.c `sqlite_config --cflags` -shared
という風にコンパイルして(これはLinuxの場合)、しかるべき場所(LD_LIBRARY_PATHが通る場所)に置いた後、sqliteのシェルで
> select load_extension("myfunc.so");
とやればいきなり使える。

sqlite3_value_textはアロケートした文字列を渡して、最終引数に開放関数を渡すというのがUDFのお作法らしい。strdupで確保したポインタは最終引数の関数でfreeする、みたいな。

動かす手順

で、今回作ったのはV8とリンクして、JSの文字列をevalしてくれるjs_evalというUDF。
多分試す人はいないと思うけど、動かすための手順を書くと

V8のビルド

V8を落としてきてビルドする。ただし、SQLiteのUDFは別に-fPICを付けなくてもおk。

js_eval.cppをコンパイル

V8をビルドしたディレクトリにもっていって
g++ -o js_eval.so js_eval.cpp `sqlite_config --cflags` -shared -Iinclude libv8.a -lpthread
そうすると、js_eval.soができるので、これをLD_LIBRARY_PATHが通ったディレクトリに置く

読み込むる

シェルに入って
> select load_extension("myfunc.so");
(※このUDF、食わせるものによってはSQLiteごと落ちるかもしれないので良い子のみんなは注意だ)

キターーーッ

すごい。
sqlite3udf1

全然
sqlite3udf2
役に立つ気がしない。
sqlite3udf3
というかSQLite力が低すぎてどうしたら面白くなるか思いつかない。これを発展させていってTEXTとかに突っ込んだJSONの中身を効率よく検索とか出来たら面白い&実用的なんだけど、道は遠そうだ。


参考
やったーJavaScriptの動くMySQLできたよー - 愛と勇気と缶ビール

しばらく 積ん読 していたこの本をちょっと眺めてみたら、 MySQL のUDFって簡単に作れるんだなー、と思った && そういや V8 って ライブラリ として簡単にリンクできるはずだな、と思い出した...

http://d.hatena.ne.jp/zentoo/20110925/1316961032
Posted at 14:15 in ソフトウェア::lang::c
Tagged as: c++, javascript, sqlite, ネタ
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2010/01/14


このエントリーをはてなブックマークに追加
なんとなくテーブルにデータがINSERTされたらGrowlされる...なんて仕組み作って見ようと思った。それだけ。
sqliteでextensionを作る。growlはWindowsのGNTPにも対応したmattn謹製gntp-sendを使う。
mattn's gntp-send at master - GitHub

command line program that send to growl using GNTP protocol.

http://github.com/mattn/gntp-send
gntp-sendはコマンドラインプログラムだけど、外部からライブラリとしても使える様にしてあります。
#include <stdlib.h>
#include <sqlite3ext.h>
#include <growl.h>

SQLITE_EXTENSION_INIT1
static void growl_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
    if (argc == 1) {
        const char *text  = (const char *)sqlite3_value_text(argv[0]);
        growl("localhost", "sqlite3", "sqlite3-trigger", "database-update", text, NULL, NULL, NULL);
    }
}
__declspec(dllexport) int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
    SQLITE_EXTENSION_INIT2(api);
    return sqlite3_create_function(db, "growl", 1, SQLITE_UTF8, (void*)db, growl_func, NULL, NULL);
}
こんなコード書いて
# gcc -shared -dll -I c:/sqlite3 -I headers growldb.c lib/libgrowl-static.a -lws2_32 -o growldb.dll
こんな風にコンパイル(Windowsの例)。
あとはテーブルにトリガー張って
sqlite> create table foo(comment text);
sqlite> select load_extension('growldb.dll');
sqlite> create trigger tri_foo
   ...> before
   ...>   insert on foo
   ...> begin
   ...>   select growl(new.comment);
   ...> end;
試してみよう!



sqlite> insert into foo values('hasegawa! xss xss');


sqlite3-growl
xssキター!

ただしinsertする側は必ずload_extension('growldb.dll')しとかないといけないので、oracleの様には行かない。
真面目な話、この方法をうまく使えばsqliteでネットワークレプリケーションとか出来そう。
えっ?誰得?.......知りません!
Posted at 00:17 in ソフトウェア::lang::c
Tagged as: c, DB, growl, sql, sqlite
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip

2009/04/16


このエントリーをはてなブックマークに追加
SQLite便利!
SQLite3におけるREGEXP演算子 - anon_193の日記

SQLite では、load_extension 関数を用いて、外部の拡張モジュールをロードすることが出来る。拡張モジュールは、いわばユーザ関数ライブラリで、SQLite3 ODBC Driver には標準で BLOB二次元マッピング拡張(sqlite3_mod_blobtoxy.dll)、外部データ取込・出力拡張(sqlite3_mod_impexp.dll)、全文検索拡張(sqlite3_mod_fts3.dll) が付属している。これらと同様にして、正規表現マッチングを行う regexp ユーザ関数を持つ拡張モジュールを制作し、ロードすれば、お目当ての REGEXP 演算子が使えるわけだ。

http://d.hatena.ne.jp/anon_193/20090114/1231935112
sqlite3_mod_regexp.cxx
#include <boost/regex.hpp>
#include <sqlite3ext.h>
extern "C" {
    SQLITE_EXTENSION_INIT1
    static void regexp_func(sqlite3_context *context, int argc, sqlite3_value **argv) {
        if (argc >= 2) {
            const char *target  = (const char *)sqlite3_value_text(argv[1]);
            const char *pattern = (const char *)sqlite3_value_text(argv[0]);
            try {
                boost::regex ereg(pattern, boost::regex_constants::perl);
                sqlite3_result_int(context, boost::regex_search(target, ereg));
            } catch (boost::regex_error &e) {
                sqlite3_result_error(context, e.what(), 0);
            }
        }
    }
    __declspec(dllexport) int sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
        SQLITE_EXTENSION_INIT2(api);
        return sqlite3_create_function(db, "regexp", 2, SQLITE_UTF8, (void*)db, regexp_func, NULL, NULL);
    }
}
VCでコンパイルしました。
# cl /EHsc -Isrc -I. -I "c:\boost_1_35_0" sqlite3_mod_regexp.cxx /LD "C:\boost_1_35_0\libs\regex\build\vc80\libboost_regex-vc80-mt-s-1_35.lib"
サンプルデータ
foo.sql
CREATE TABLE foo(id integer primary key, value text);
INSERT INTO "foo" VALUES(1,'abc');
INSERT INTO "foo" VALUES(2,'def');
INSERT INTO "foo" VALUES(3,'あいうえお');
INSERT INTO "foo" VALUES(4,'かきくけこ');
INSERT INTO "foo" VALUES(5,'さしすせそ');
utf-8で保存して下さい
# cat foo.sql | sqlite3 foo.db
そしてPerlのコード
use strict;
use warnings;
use utf8;
use YAML;
use DBIx::Simple;

my $db = DBIx::Simple->connect("dbi:SQLite:dbname=c:/foo.db", "", "")
    or die DBIx::Simple->error;

$db->func(1, "enable_load_extension");

my $result = $db->query("select load_extension('/sqlite3_mod_regexp.dll')")
    or die DBIx::Simple->error;
warn Dump $db->query("select * from foo where value regexp '^[あか]'")->hashes;
dbのパスとdllのパスは指定して下さい
実行すると...
---
id: 3
value: あいうえお
---
id: 4
value: かきくけこ
スゲーーーー便利!
Posted at 11:10 in ソフトウェア::lang::perl
Tagged as: perl, sqlite, windows
Bookmarks: add to hatena add to hatena | add to delicious.com | add to livedoor.clip add to livedoor.clip