2015-06-29 68 views
0

在SQLite中處理blob時,是否有處理類型錯誤的好方法?例如,以下代碼註冊了兩個函數create_vectordisplay_vector。基本上,create_vector存儲std::vector作爲BLOB和display_vector將這個BLOB成文本,這樣我們就可以看出來:如何在SQLite中處理blob時處理類型錯誤?

/* In order to use 

sqlite> .load "./blob.so" 
sqlite> select display_vector(create_vector()); 
[ 1.200000, 3.400000, 5.600000, 7.800000, 9.100000 ] 

*/ 

#include <string> 
#include <sqlite3ext.h> 
SQLITE_EXTENSION_INIT1 

extern "C" { 
    int sqlite3_blob_init(
     sqlite3 * db, 
     char ** err, 
     sqlite3_api_routines const * const api 
    ); 
} 

// Cleanup handler that deletes an array 
template <typename T> 
void array_cleanup(void * v) { 
    delete [] static_cast <T *> (v); 
} 

// Creates and returns a std::vector as a blob 
static void create_vector(
    sqlite3_context *context, 
    int argc, 
    sqlite3_value **argv 
){ 
    // Create a dummy vector 
    auto * v = new double[5] {1.2,3.4,5.6,7.8,9.10}; 

    // Either cleanup works 
    sqlite3_result_blob(context,v,sizeof(double[5]),array_cleanup <double>); 
} 

// Converts a std::vector into text 
static void display_vector(
    sqlite3_context *context, 
    int argc, 
    sqlite3_value **argv 
){ 
    // Grab the vector. Note, if this is not a vector, then sqlite will 
    // almost certainly segfault. 
    auto const * const v =static_cast <double const * const> (
     sqlite3_value_blob(argv[0])); 

    // Assuming we have a vector, convert it into a string 
    auto s = std::string("[ "); 
    for(unsigned i=0;i<5;i++) { 
     // If we're not on the first element, add a comma 
     if(i>0) s += ", "; 

     // Add the number 
     s += std::to_string(v[i]); 
    } 
    s += " ]"; 

    // Return the text 
    sqlite3_result_text(
     context,sqlite3_mprintf("%s",s.c_str()),s.size(),sqlite3_free); 
} 

// Register our blob functions 
int sqlite3_blob_init(
    sqlite3 *db, 
    char **err, 
    sqlite3_api_routines const * const api 
){ 
    SQLITE_EXTENSION_INIT2(api) 

    // Register the create_vector function 
    if(int ret = sqlite3_create_function(
     db, "create_vector", 0, SQLITE_ANY, 0, create_vector, 0, 0) 
    ) { 
     *err=sqlite3_mprintf("Error registering create_vector: %s", 
      sqlite3_errmsg(db)); 
     return ret; 
    } 

    // Register the display_vector function 
    if(int ret = sqlite3_create_function(
     db, "display_vector", 1, SQLITE_ANY, 0, display_vector, 0, 0) 
    ) { 
     *err=sqlite3_mprintf("Error registering display_vector: %s", 
      sqlite3_errmsg(db)); 
     return ret; 
    } 

    // If we've made it this far, we should be ok 
    return SQLITE_OK; 
} 

我們可以編譯這個:

$ make 
g++ -g -std=c++14 blob.cpp -shared -o blob.so -fPIC 

現在,如果我們使用這些作爲標榜,一切工作正常:

sqlite> .load "./blob.so" 
sqlite> select display_vector(create_vector()); 
[ 1.200000, 3.400000, 5.600000, 7.800000, 9.100000 ] 

然而,如果我們試圖在非矢量使用display_vector,我們段錯誤:

sqlite> .load "./blob.so" 
sqlite> select display_vector(NULL); 
Segmentation fault 

真的,問題是,在static_cast矢量display_vector是不正確的。無論如何,是否有一種很好的方法檢查blob的類型,甚至保證我們有一個blob?當一個新擴展需要某種類型的輸入時,是否有一種防止段錯誤的好方法?

+0

是不是'sizeof(v)'指針的大小? –

+0

@CL。你是對的。那是個錯誤。我修改了這個例子來存儲一個雙精度數組。它仍然是段錯誤。 – wyer33

回答