SQLite3: вставка BLOB с символами NULL в C ++ - PullRequest
8 голосов
/ 01 января 2009

Я работаю над разработкой C ++ API, который использует специально разработанные плагины взаимодействовать с различными механизмами баз данных, используя их API и специфический SQL синтаксис.

В настоящее время я пытаюсь найти способ вставки больших двоичных объектов, но поскольку NULL завершающий символ в C / C ++, BLOB становится усеченным при построении INSERT INTO строка запроса. До сих пор я работал с

//...
char* sql;
void* blob;
int len;
//...
blob = some_blob_already_in_memory;
len = length_of_blob_already_known;
sql = sqlite3_malloc(2*len+1);
sql = sqlite3_mprintf("INSERT INTO table VALUES (%Q)", (char*)blob);
//...

Я ожидаю, что, если это вообще возможно сделать в интерактивной консоли SQLite3, можно создать строку запроса с правильно экранированными NULL символами. Может быть, есть способ сделать это с помощью стандартного SQL, который также поддерживается синтаксисом SQLite SQL?

Конечно, кто-то должен был сталкиваться с такой же ситуацией и раньше. Я погуглил и нашел несколько ответов, но был на других языках программирования (Python).

Заранее благодарим вас за отзыв.

Ответы [ 3 ]

9 голосов
/ 03 января 2009

Еще раз спасибо всем за ваш отзыв. На этот раз я сообщаю, как я решил проблему с помощью указаний, приведенных здесь. Надеюсь, это поможет другим в будущем.

Как указывалось в первых трех постерах, я использовал подготовленные высказывания & mdash; кроме того, потому что я также был заинтересован в получении типов данных столбцов, а простой sqlite3_get_table() не подойдет.

После подготовки оператора SQL в виде следующей константной строки:

INSERT INTO table VALUES(?,?,?,?);

остается привязкой соответствующих значений. Это делается путем выдачи столько вызовов sqlite3_bind_blob(), сколько столбцов. (Я также прибегнул к sqlite3_bind_text() для других «простых» типов данных, потому что API, над которым я работаю, может переводить целые / двойные / и т. Д. В строку). Итак:

void* blobvalue[4];
int blobsize[4];
char *tail, *sql="INSERT INTO table VALUES(?,?,?,?)";
sqlite3_stmt *stmt=0;
sqlite3 *db;
/* ... */
db=sqlite3_open("sqlite.db");
sqlite3_prepare_v2(db, 
                   sql, strlen(sql)+1, 
                   &stmt, &tail);
for(int i=0; i<4; i++)
    sqlite3_ bind_ blob(stmt, 
                        i+1, blobvalue[i], blobsize[i], 
                        SQLITE_TRANSIENT);
if(sqlite3_step(stmt)!=SQLITE_DONE) 
    printf("Error message: %s\n", sqlite3_errmsg(db));
sqlite3_finalize(stmt);
sqlite3_close(db);

Обратите внимание, что некоторые функции (sqlite3_open_v2(), sqlite3_prepare_v2()) появляются в более поздних версиях SQLite (я полагаю, 3.5.x и более поздние версии).

8 голосов
/ 02 января 2009

Вы захотите использовать эту функцию с подготовленным оператором.

int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*));

В C / C ++ стандартным способом работы со значениями NULL в строках является либо сохранение начала строки и длины, либо сохранение указателя на начало строки и один на конец строки.

1 голос
/ 01 января 2009

Вы хотите предварительно скомпилировать оператор sqlite_prepare_v2(), а затем связать большой двоичный объект с помощью sqlite3_bind_blob(). Обратите внимание, что оператор, к которому вы привязываетесь, будет INSERT INTO table VALUES (?) .

...