C SQLite在绑定参数时插入BLOB而不是字符串,反之亦然

C SQLite在绑定参数时插入BLOB而不是字符串,反之亦然,c,sqlite,text,blob,C,Sqlite,Text,Blob,因此,我在C中使用SQLite进行参数绑定时遇到了一些问题。我使用sqlite3_bind_*函数将blob和字符串插入数据库。然而,在插入之后,我用SQLiteBrowser检查了数据库,惊奇地发现所有类型都乱七八糟!下面是一些应该重现效果的示例代码 此块创建表 const char *TABLE_NAME = "PASSWORD_ENTRY"; const char *USER_ID_COLUMN_NAME = "USER_ID"; const char *INDEX_COLUMN_NAME

因此,我在C中使用SQLite进行参数绑定时遇到了一些问题。我使用sqlite3_bind_*函数将blob和字符串插入数据库。然而,在插入之后,我用SQLiteBrowser检查了数据库,惊奇地发现所有类型都乱七八糟!下面是一些应该重现效果的示例代码

  • 此块创建表

    const char *TABLE_NAME = "PASSWORD_ENTRY";
    const char *USER_ID_COLUMN_NAME = "USER_ID";
    const char *INDEX_COLUMN_NAME = "INDEX_VALUE";
    const char *SERVICE_COLUMN_NAME = "SERVICE";
    const char *SYM_ENC_KEY_COLUMN_NAME = "SYM_ENC_KEY";
    const char *ASYM_ENC_KEY_COLUMN_NAME = "ASYM_ENC_KEY";
    const char *TIMESTAMP_COLUMN_NAME = "TIMESTAMP";
    
    /* CREATE TABLE IF NOT EXISTS TABLE_NAME (
            USER_ID_COLUMN_NAME INTEGER, 
            INDEX_COLUMN_NAME INTEGER, 
            SERVICE_COLUMN_NAME TEXT, 
            SYM_ENC_KEY_COLUMN_NAME BLOB, 
            ASYM_ENC_KEY_COLUMN_NAME BLOB,
            TIME_STAMP_COLUMN_NAME BLOB, 
            PRIMARY KEY (USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME)); 
    */
    
    char *f = "CREATE TABLE IF NOT EXISTS %s (%s INTEGER, %s INTEGER, %s TEXT, %s BLOB, %s BLOB, %s BLOB, PRIMARY KEY (%s, %s));";
    
    char *s = malloc(snprintf(NULL, 0, f, TABLE_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME, SERVICE_COLUMN_NAME, SYM_ENC_KEY_COLUMN_NAME, ASYM_ENC_KEY_COLUMN_NAME, TIMESTAMP_COLUMN_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME) + 1);
    
    sprintf(s, f, TABLE_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME, SERVICE_COLUMN_NAME, SYM_ENC_KEY_COLUMN_NAME, ASYM_ENC_KEY_COLUMN_NAME, TIMESTAMP_COLUMN_NAME, USER_ID_COLUMN_NAME, INDEX_COLUMN_NAME);
    
    const char *DB_NAME = "passwordmanager.db";
    
    sqlite3* db;
    int r = 0;
    
    // Get the database
    r = sqlite3_open(DB_NAME, &db);
    if (r) {
            printf("Error opening database: %s\n", sqlite3_errmsg(db));
            return NULL;
    }
    printf("Database opened.\n");
    
    r = sqlite3_prepare_v2(db, sql, strlen(sql), &stmt, NULL);
    if (r) {
            printf("Error preparing create table statement: %s\n", sqlite3_errmsg(db));
            return 1;
    }
    
    r = sqlite3_step(stmt);
    if (r != 101 && r) {
            printf("Error executing create table statement: %s\n", sqlite3_errmsg(db));
            return 1;
    }
    printf("Password entry table ready.\n");
    sqlite3_finalize(stmt);
    
  • 现在已经完成了,我将给您一个插入示例

    sqlite3_stmt *stmt2;
    long userId = 50l;
    short index = 2;
    long timestamp = 100l;
    char *service = "stackoverflow.com";
    const int SYM_ENC_KEY_LEN = 10;
    const int ASYM_ENC_KEY_LEN = 11;
    char *symEncKey = "symEncKey";
    char *asymEncKey = "asymEncKey";
    
    char *f = "INSERT INTO PASSWORD_ENTRY (USER_ID, INDEX_VALUE, SERVICE, TIMESTAMP, SYM_ENC_KEY, ASYM_ENC_KEY) VALUES (?, ?, ?, ?, ?, ?);";
    
    printf("SQL ready.\n");
    
    r = sqlite3_prepare_v2(db, f, strlen(f), &stmt2, NULL);
    if (r != 0) {
            printf("Error preparing addition statement: %s\n", sqlite3_errmsg(db));
            sqlite3_finalize(stmt2);
            sqlite3_close(db);
            return;
    }
    printf("Prepared the addition statement, binding...\n");
    
    sqlite3_bind_int64(stmt2, 1, (sqlite3_int64) userId);
    sqlite3_bind_int(stmt2, 2, (int) index);
    sqlite3_bind_text(stmt2, 3, service, strlen(service) + 1, 0);
    sqlite3_bind_int64(stmt2, 4, (sqlite_int64) timestamp);
    sqlite3_bind_blob(stmt2, 5, (void *) symEncKey, SYM_ENC_KEY_LEN, 0);
    sqlite3_bind_blob(stmt2, 6, (void *) asymEncKey, ASYM_ENC_KEY_LEN, 0);
    
    // Execute the statement
    r = sqlite3_step(stmt2);
    if (r != 101) {
            printf("Error executing addition statement: %s\n", sqlite3_errmsg(db));
            sqlite3_finalize(stmt2);
            sqlite3_close(db);
            return;
    }
    printf("Executed the addition statement.\n");
    
    sqlite3_finalize(stmt2);
    sqlite3_close(db);
    
  • 现在,如果您想使用SQLiteBrowser或任何类似工具查看数据库,只要您和我一样幸运,您就会看到列服务包含一个BLOB,SYM_ENC_KEY列包含一个字符串,而不管我使用的是相反的sqlite3_bind_*函数。有人知道这是怎么发生的吗?如果您需要更多信息,请询问。我是一个新的海报

    sqlite3_bind_text(stmt2, 3, service, strlen(service) + 1, 0);
    
    零终止符不被视为字符串数据的一部分。 删除
    +1
    ,或者更好,只需给出
    -1

    最后一个参数是错误的;必须提供析构函数,或
    SQLITE\u TRANSIENT
    SQLITE\u STATIC

    (调用
    \u blob
    也有同样的问题。)


    但是,命令行shell中的
    .dump
    命令的输出包含以下内容:

    插入“密码输入”值(50,2,'stackoverflow.com',X'73796D456E634B657900',X'6173796D456E634B657900',100);
    

    这是正确的。没有数据类型问题。

    此代码无法编译。感谢您这么快返回!我做了您指定的更改,服务名称列似乎工作正常,但是根据SQLiteBrowser,SYM_ENC_KEY列仍在存储字符串。可能这只是SQLiteBrowser中的一个错误,因为您可以使用命令行工具检查语句,并且插入了正确的类型。无论如何,我会接受你的回答,谢谢你的帮助!