2009-01-01 7 views
8

Je travaille sur le développement d'une API C++ qui utilise des plugins personnalisés pour interfacer avec différents moteurs de bases de données en utilisant leurs API et la syntaxe spécifique SQL .SQLite3: Insérer BLOB avec des caractères NULL en C++

Actuellement, je suis tenté de trouver un moyen d'insertion BLOBs, mais depuis NULL est le caractère de terminaison en C/C++, le blob devient tronquée lors de la construction l'INSERT INTO chaîne de requête. Jusqu'à présent, j'ai travaillé avec

//... 
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); 
//... 

Je pense que, si elle est du tout possible de le faire dans la console interactive SQLite3, il devrait être possible de construire la chaîne de requête avec correctement échappé NULL caractères. Peut-être y a-t-il un moyen de le faire avec le SQL standard qui est également supporté par la syntaxe SQLite SQL?

Certes, quelqu'un doit avoir déjà fait face à la même situation. J'ai googlé et trouvé quelques réponses mais j'étais dans d'autres langages de programmation (Python).

Merci d'avance pour vos commentaires.

+0

Cette page (http://www.sqlite.org/c3ref/bind_blob.html) semble répertorier toutes les fonctions dont vous avez besoin. – zvrba

Répondre

8

Vous devez utiliser cette fonction avec une instruction préparée.

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

en C/C++, la manière standard de traiter avec les valeurs NULL dans les chaînes est soit stocker le début de la chaîne et une longueur, ou stocker un pointeur vers le début d'une chaîne et un à la fin de la chaîne

1

Vous souhaitez précompiler l'instruction sqlite_prepare_v2(), puis lier le blob à l'aide de sqlite3_bind_blob(). Notez que l'instruction à laquelle vous vous connectez sera INSERT INTO table VALUES (?).

+0

Je ne suis pas sûr de cela, mais je n'ai qu'un seul "?" le marqueur de lieu fonctionne? Ou est-il nécessaire d'avoir autant que le nombre de champs de la table? – jbatista

+1

Oui, vous devrez faire correspondre le nombre de champs si vous le faites de cette façon. –

9

Merci encore pour vos commentaires. Cette fois, je rapporte comment j'ai résolu le problème avec l'aide des indications fournies ici. Espérons que cela aidera les autres à l'avenir. Comme suggéré par les trois premières affiches, j'ai utilisé des instructions préparées — en plus parce que je voulais également obtenir les types de données des colonnes, et un simple sqlite3_get_table() ne ferait pas.

Après avoir préparé l'instruction SQL sous la forme de la chaîne constante suivante:

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

il reste le liant des valeurs correspondantes. Ceci est fait en émettant autant d'appels sqlite3_bind_blob() que les colonnes. (J'ai également eu recours à sqlite3_bind_text() pour d'autres types de données "simples" car l'API sur laquelle je travaille peut traduire des entiers/doubles/etc en une chaîne). Alors:

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); 

Notez aussi que certaines fonctions (sqlite3_open_v2(), sqlite3_prepare_v2()) apparaissent sur les versions ultérieures SQLite (je suppose que 3.5.x et versions ultérieures).

+1

Manquant slqite3_close (db) – kibab

+0

@kibab Merci, corrigé. (BTW, vous auriez été invité à l'avoir amélioré vous-même.) – jbatista

+0

Je ne savais pas que je peux éditer d'autres messages :) Merci, bon à savoir. – kibab

Questions connexes