Is there a good way to handle errors in a select statement when attempting an insert or fail? Specifically, I want to insert elements into a table, but the select statement used to generate these elements is failing. I would like to have all the elements where the select statement succeeded to be inserted, but for the overall statement to fail. I thought that insert or fail would do this, but it does not. More specifically, imagine if we defined a new SQLite function "log"
#include <string>
#include <sqlite3ext.h>
#include <cmath>
SQLITE_EXTENSION_INIT1
extern "C" {
int sqlite3_log_init(
sqlite3 * db,
char ** err,
sqlite3_api_routines const * const api
);
}
// Compute the log of the input
void mylog(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
// Grab the number
auto num = sqlite3_value_double(argv[0]);
// If positive, take the log
if(num > 0.)
sqlite3_result_double(context, log(num));
// Otherwise, throw an error
else {
auto msg = std::string("Can't take the log of a nonpositive number");
sqlite3_result_error(context,msg.c_str(),msg.size());
}
}
// Initialize the functions
int sqlite3_log_init(
sqlite3 *db,
char **err,
sqlite3_api_routines const * const api
){
SQLITE_EXTENSION_INIT2(api)
// Register the log function
if( int ret = sqlite3_create_function(
db, "log", 1, SQLITE_ANY, 0, mylog, 0, 0)
) {
*err=sqlite3_mprintf("Error registering log: %s",
sqlite3_errmsg(db));
return ret;
}
// If we've made it this far, we should be ok
return SQLITE_OK;
}
This can be compiled with
g++ -std=c++14 log.cpp -shared -o log.so -fPIC
Basically, the above function takes the log of its element. For example,
sqlite> select log(1);
0.0
sqlite> select log(0);
Error: Can't take the log of a nonpositve number
Now, consider the following sequence of SQL operations
sqlite> .load "./log.so"
sqlite> create table foo (num real);
sqlite> insert into foo values (2.), (1.), (0.);
sqlite> create table bar (num real);
sqlite> insert or fail into bar select log(num) from foo;
Error: Can't take the log of a nonpositve number
sqlite> select * from bar;
sqlite>
Basically, the table bar is empty because the select statement failed on 0. What I want to have happen is for the table bar to contain the elements log(2.) and log(1.), but the error to still be thrown. Is there a way to have that happen?
Aucun commentaire:
Enregistrer un commentaire