2014-01-23 10:56:01 +09:00
# include <string>
# include <sstream>
2020-04-16 01:45:59 -04:00
# include <sqlite3.h>
2014-01-23 10:56:01 +09:00
# 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 ;
}
}