PostgreSQLに興味がある人向けにまとめてみた。|PostgreSQL|お仕事メモ|Pictnotesそれはワクテカ過ぎる...
http://www.pictnotes.jp/memo/archives/6
- Q. FDWってなによ?
- A. FDW(Foreign Data Wrappe),外部データラッパっていうやつで、SQL/MED(Management of External Data)の規格の一つで簡単にいうと、PostgreSQLにQUERYを発行したら、あら不思議、外部の(たとえばMySQLとかCSV)データが取得できるという変態機能。
twitterAPIに変更あるらしいから今後はわからにけど、twitterのデータを取ってくるとかもできる。というかラッパーが用意されてる。(ちなみに使ってみたら楽しかったw)
だがしかし SQLite3 でも出来る!きっと出来る!
#include <string>
#include <sstream>
#include <sqlite3.h>
#include <sqlite3ext.h>
#include <curl/curl.h>
#include "picojson.h"
#ifdef _WIN32
# define EXPORT __declspec(dllexport)
#else
# define EXPORT
#endif
SQLITE_EXTENSION_INIT1;
typedef struct {
char* data; // response data from server
size_t size; // response size of data
} MEMFILE;
MEMFILE*
memfopen() {
MEMFILE* mf = (MEMFILE*) malloc(sizeof(MEMFILE));
if (mf) {
mf->data = NULL;
mf->size = 0;
}
return mf;
}
void
memfclose(MEMFILE* mf) {
if (mf->data) free(mf->data);
free(mf);
}
size_t
memfwrite(char* ptr, size_t size, size_t nmemb, void* stream) {
MEMFILE* mf = (MEMFILE*) stream;
int block = size * nmemb;
if (!mf) return block; // through
if (!mf->data)
mf->data = (char*) malloc(block);
else
mf->data = (char*) realloc(mf->data, mf->size + block);
if (mf->data) {
memcpy(mf->data + mf->size, ptr, block);
mf->size += block;
}
return block;
}
char*
memfstrdup(MEMFILE* mf) {
char* buf;
if (mf->size == 0) return NULL;
buf = (char*) malloc(mf->size + 1);
memcpy(buf, mf->data, mf->size);
buf[mf->size] = 0;
return buf;
}
static int
my_connect(sqlite3 *db, void *pAux, int argc, const char * const *argv, sqlite3_vtab **ppVTab, char **c) {
std::stringstream ss;
ss << "CREATE TABLE " << argv[0]
<< "(id text, screen_name text, tweet text)";
int rc = sqlite3_declare_vtab(db, ss.str().c_str());
*ppVTab = (sqlite3_vtab *) sqlite3_malloc(sizeof(sqlite3_vtab));
memset(*ppVTab, 0, sizeof(sqlite3_vtab));
return rc;
}
static int
my_create(sqlite3 *db, void *pAux, int argc, const char * const * argv, sqlite3_vtab **ppVTab, char **c) {
return my_connect(db, pAux, argc, argv, ppVTab, c);
}
static int my_disconnect(sqlite3_vtab *pVTab) {
sqlite3_free(pVTab);
return SQLITE_OK;
}
static int
my_destroy(sqlite3_vtab *pVTab) {
sqlite3_free(pVTab);
return SQLITE_OK;
}
typedef struct {
sqlite3_vtab_cursor base;
int index;
picojson::value* rows;
} cursor;
static int
my_open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) {
MEMFILE* mf;
CURL* curl;
char* json;
mf = memfopen();
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://api.twitter.com/1/statuses/public_timeline.json");
curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
curl_easy_perform(curl);
curl_easy_cleanup(curl);
picojson::value* v = new picojson::value;
std::string err;
picojson::parse(*v, mf->data, mf->data + mf->size, &err);
memfclose(mf);
if (!err.empty()) {
delete v;
std::cerr << err << std::endl;
return SQLITE_FAIL;
}
cursor *c = (cursor *)sqlite3_malloc(sizeof(cursor));
c->rows = v;
c->index = 0;
*ppCursor = &c->base;
return SQLITE_OK;
}
static int
my_close(cursor *c) {
delete c->rows;
sqlite3_free(c);
return SQLITE_OK;
}
static int
my_filter(cursor *c, int idxNum, const char *idxStr, int argc, sqlite3_value **argv) {
c->index = 0;
return SQLITE_OK;
}
static int
my_next(cursor *c) {
c->index++;
return SQLITE_OK;
}
static int
my_eof(cursor *c) {
return c->index >= c->rows->get<picojson::array>().size() ? 1 : 0;
}
static int
my_column(cursor *c, sqlite3_context *ctxt, int i) {
picojson::value v = c->rows->get<picojson::array>()[c->index];
picojson::object row = v.get<picojson::object>();
const char* p = NULL;
switch (i) {
case 0:
p = row["id"].to_str().c_str();
break;
case 1:
p = row["user"].get<picojson::object>()["screen_name"].to_str().c_str();
break;
case 2:
p = row["text"].to_str().c_str();
break;
}
sqlite3_result_text(ctxt, strdup(p), strlen(p), free);
return SQLITE_OK;
}
static int
my_rowid(cursor *c, sqlite3_int64 *pRowid) {
*pRowid = c->index;
return SQLITE_OK;
}
static int
my_bestindex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo) {
return SQLITE_OK;
}
static const sqlite3_module module = {
0,
my_create,
my_connect,
my_bestindex,
my_disconnect,
my_destroy,
my_open,
(int (*)(sqlite3_vtab_cursor *)) my_close,
(int (*)(sqlite3_vtab_cursor *, int, char const *, int, sqlite3_value **)) my_filter,
(int (*)(sqlite3_vtab_cursor *)) my_next,
(int (*)(sqlite3_vtab_cursor *)) my_eof,
(int (*)(sqlite3_vtab_cursor *, sqlite3_context *, int)) my_column,
(int (*)(sqlite3_vtab_cursor *, sqlite3_int64 *)) my_rowid,
NULL, // my_update
NULL, // my_begin
NULL, // my_sync
NULL, // my_commit
NULL, // my_rollback
NULL, // my_findfunction
NULL, // my_rename
};
static void
destructor(void *arg) {
return;
}
extern "C" {
EXPORT int
sqlite3_extension_init(sqlite3 *db, char **errmsg, const sqlite3_api_routines *api) {
SQLITE_EXTENSION_INIT2(api);
sqlite3_create_module_v2(db, "twitter_public_timeline", &module, NULL, destructor);
return 0;
}
}
picojson を使うので適当に持ってきて下さい。このソースを
sqlite3_twit.cxx
として
$ g++ -I. -g -o sqlite3_twit.dll -shared sqlite3_twit.cxx -lcurldll
の様にコンパイルする。unix な人は... 調べて下さい。さて...
$ sqlite3
SQLite version 3.7.14 2012-09-03 15:42:36
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
SQLiteのシェルに入ったら
sqlite> select load_extension("sqlite3_twit.dll");
load_extension("sqlite3_twit.dll")
----------------------------------
拡張をロードして
sqlite> create virtual table tbl using twitter_public_timeline(id, screen_name, text);
仮想テーブルを作る。あとは...
sqlite> select * from tbl;
id screen_name tweet
------------------ ------------ ---------------------------------------------------------------------------------------------
248056468924928000 sosomustafa2 الحياة بسيطه جدا لدرجة أن الابتسامه قد تجعلك محبوب جدا ♡"
248056468727808000 nurulauliad Sekalinya dateng, dateng semua. Sekalinya pergi, pergi semua. Itu lah sebab kenapa hidup penuh pilihan.
248056468421632000 ZaldivarSkat ¡HOY HOY HOY! Extreno de O.N.I.F.C de @RealWizKhalifa
248056468291584000 chimpungdila Ciye! "@putuderism: Hey 1530 QL, i miss you so badly :'))"
248056467767296000 44Velboo 268とかプロボウラー並の人がいる(^_^;)
248056467154944000 kevintumongg Karepmu her RT @KurniawanHerdi: Mau banget ga mong? RT @kevintumonggi: @KurniawanHerdi folbeck her
248056467045888000 rnbanyu Detik detik
248056466739712000 iiiFoN [HD] The Voice Thailand : Week2 (Full Version) 16 Sep 2012: http://t.co/mRIaKDuy via @youtube
248056465582080000 CarbonQ8e ياكـــم نفـــسٍ عـــن هـــوا الحـــب طابـــت
248056465166848000 WhoIsVARRI_ I'm just Boolin how i B Boolin !
248056463069696000 iSwiftCyrus Photo: http://t.co/qAcDMm1c
248056463048704000 IGORNOKALT Baixei o ringtone do gummy bear :9
248056462130176000 meowkikocel #MentionSomeoneVerySpecial @Mistacey :)
248056462109184000 xFatehx just got back from NVBA , phhewww what a great match :D
248056461912064000 snags17 「倭」を日本の蔑称として使いたがるのは、「現代では」、中国人より韓国<e4><ba>
248056461803008000 hendraMirvan RT @gadasianipar: RT @febrinacitra: Ket biyen nonton sketsa kok rak tau ngguyu blas to.... (‾▿‾")
248056460972544000 _Azrie_ begitu lah gaya nya , online , tapi hanya memerhatikan TL.
248056460557312000 imbaked_ This one of those morning were I smoke a blunt nd watch Kevin Hart
248056459814912000 psanso + RT“@damiaborras: El rei diu que hem de remar tots… Deu tenir el Fortuna espatllat.”
sqlite>
キターーー!もちろん
sqlite> select * from tbl where tweet like '%twitter%';
id screen_name tweet
------------------ ------------ -----------
248059202780672000 Baby_Nandos_ New Twitter
where区だって使えるんだぜ!public timeline速過ぎるから毎回違うテーブル内容なんだぜ!って事で、データベースは MySQL でも PostgreSQL でもなく、SQLite に決まり!