0
在SQLite中處理blob時,是否有處理類型錯誤的好方法?例如,以下代碼註冊了兩個函數create_vector
和display_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?當一個新擴展需要某種類型的輸入時,是否有一種防止段錯誤的好方法?
是不是'sizeof(v)'指針的大小? –
@CL。你是對的。那是個錯誤。我修改了這個例子來存儲一個雙精度數組。它仍然是段錯誤。 – wyer33