尝试插入或失败时如何处理select语句中的错误?

时间:2015-07-17 22:52:35

标签: sql sqlite

尝试插入或失败时,是否有一种处理select语句错误的好方法?具体来说,我想将元素插入表中,但用于生成这些元素的select语句失败。我想拥有成功插入select语句的所有元素,但是整个语句失败了。我认为插入或失败会这样做,但事实并非如此。更具体地说,假设我们定义了一个新的SQLite函数“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;
}

可以使用

编译
g++ -std=c++14 log.cpp -shared -o log.so -fPIC

基本上,上面的函数获取其元素的日志。例如,

sqlite> select log(1);
0.0
sqlite> select log(0);
Error: Can't take the log of a nonpositve number

现在,考虑以下SQL操作序列

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> 

基本上,表格栏是空的,因为select语句在0上失败。我想要的是表格栏包含元素log(2。)和log(1。),但错误仍然是被抛出有没有办法让这种情况发生?

1 个答案:

答案 0 :(得分:1)

SQLite的ON CONFLICT clause仅适用于UNIQUE,NOT NULL,CHECK和PRIMARY KEY约束,因此您将无法使用INSERT或IGNORE。

一旦用户定义的函数返回错误,就无法抑制它。

你可以说函数的结果是未定义的,让它返回NULL(然后你可以过滤掉它)。

或者,只获取那些具有有效值的行:

INSERT INTO bar SELECT log(num) FROM foo WHERE num > 0;