123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- #include <string>
- #include <sstream>
- #include <sqlite3-binding.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 int, full_name text, description text, html_url 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;
- CURLcode res = CURLE_OK;
- char error[CURL_ERROR_SIZE] = {0};
- char* cert_file = getenv("SSL_CERT_FILE");
- mf = memfopen();
- curl = curl_easy_init();
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1);
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, "curl/7.29.0");
- curl_easy_setopt(curl, CURLOPT_URL, "https://api.github.com/repositories");
- if (cert_file)
- curl_easy_setopt(curl, CURLOPT_CAINFO, cert_file);
- curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
- curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, mf);
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memfwrite);
- res = curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- if (res != CURLE_OK) {
- std::cerr << error << std::endl;
- return SQLITE_FAIL;
- }
- 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["full_name"].to_str().c_str();
- break;
- case 2:
- p = row["description"].to_str().c_str();
- break;
- case 3:
- p = row["html_url"].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, "github", &module, NULL, destructor);
- return 0;
- }
- }
|