Pourquoi dois-je obtenir un SQLITE_MISUSE : de l'erreur de Mémoire?
Je suis en train d'écrire un iOS application qui accède directement SQLite
. J'ai fait ce genre de chose de nombreuses fois sur Android, donc j'ai du mal à voir où est mon erreur se situe - toutefois, mes plaquettes sont de retour le SQLITE_MISUSE
d'erreur (code 21), avec le message "out of Memory". Ci-dessous sont les étapes que j'ai prises à me conduire à cette insertion.
Tout d'abord, le la création de la table:
NSString *sql = @"CREATE TABLE IF NOT EXISTS UsersTable (lastName TEXT,id TEXT PRIMARY KEY NOT NULL,picture BLOB,firstName TEXT,age TEXT,email TEXT,sex TEXT,height TEXT,weight TEXT)";
//create the database if it does not yet exist
NSFileManager *filemgr = [NSFileManager defaultManager];
if ([filemgr fileExistsAtPath: path ] == NO)
{
const char *dbpath = [path UTF8String];
//This was if (sqlite3_open(dbpath, &store) == SQLITE_OK) , but it has not made a difference.
if (sqlite3_open_v2(dbpath, &store, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL) == SQLITE_OK)
{
char *errMsg = NULL;
const char *sql_stmt = [sql UTF8String];
if (sqlite3_exec(store, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK)
{
NSLog(@"Failed to create table: %s", errMsg);
}
if (errMsg)
sqlite3_free(errMsg);
}
else
{
NSLog(@"Failed to open/create database");
}
}
Prochain, le insérer (en utilisant l'adresse e-mail de l'ID utilisateur):
INSERT INTO UsersTable (id,lastName,firstName,email) VALUES ("[email protected]","Smith","John","[email protected]")
Je suis en utilisant un sélecteur pour l'ensemble de la base de données des interactions, de sorte que le texte ci-dessus est passé ici:
-(int)execSQL:(NSString *)statement
{
NSLog(@"%@",statement);
const char *insert_stmt = [statement UTF8String];
sqlite3_stmt *stmnt;
sqlite3_prepare_v2(store, insert_stmt, -1, &stmnt, NULL);
int result = sqlite3_step(stmnt);
sqlite3_finalize(stmnt);
if (result != SQLITE_OK)
{
NSLog(@"Error: %s", sqlite3_errmsg(store));//This prints "Error: out of memory"
}
return result;
}
Ce que je fais mal?
- Obtenez le message d'erreur.
NSLog(@"Error: %s", sqlite3_errmsg(store));
. - sqlite s'attend à des valeurs de texte pour être entre guillemets simples, pas de guillemets doubles.
- Une dernière chose - juste au cas où - ne pas utiliser un format de chaîne pour créer vos instructions SQL. La préparation de la déclaration d'utiliser ensuite
sqlite3_bind_xxx
de lier la valeur dans la requête.INSERT INTO table (c1, c2, c2) VALUES (?, ?, ?)
. Les appels àsqlite3_bind_xxx
remplacera le?
avec la bonne valeur. Cela garantit les valeurs sont correctement cité et caractères spéciaux sont échappées. - La "mémoire" d'erreur signifie presque toujours que votre base de données (pointeur de votre
sqlite3 *
variable) n'a pas été mis correctement avec un appel àsqlite3_open_v2
. - J'ai ajouté le code que j'utilise pour ouvrir la base de données, et modifier, à l'aide de
sqlite3_open
àsqlite3_open_v2
, mais reçois toujours le même message d'erreur. Toute autre pointeurs? (Je suis actuellement en train de travailler sur vos autres suggestions) - Avez-vous vérifié que la base de données est ouvert correctement et par le temps que vous appelez le code pour l'insérer, votre
store
variable est toujours correctement le programme d'installation à partir de la base de données ouverte? En outre, initialiserstore
àNULL
juste avant l'appel àsqlite3_open
et de nouveau après l'appel desqlite3_close
. - J'ai mis
store
àNULL
avant mon ouverture, mais ça n'aide pas. Je n'ai pas l'appelersqlite3_close
jusqu'à ce que mon objet est libéré par le garbage collector. N'est-ce que ce doit être appelée après chaque instruction sql? - Voir Rob réponse. Vous n'êtes pas l'ouverture de la base de données si le fichier existe déjà. Vous devriez appeler
sqlite3_open_v2
si elle existe ou pas. Vous souhaitez simplement créer les tables si ça n'existait pas encore.
Vous devez vous connecter pour publier un commentaire.
Ouvrir votre routine est seulement à la création/ouverture de la base de données si la base de données n'existe pas. Votre base de données sans doute existe déjà et donc votre routine n'est même pas de l'ouvrir.
Bas de ligne, si vous essayez d'appeler SQLite fonctions sans ouvrir la base de données, vous obtiendrez la
SQLITE_MISUSE
code de retour (ce qui indique que l'SQLite fonctions n'ont pas été appelés dans le bon ordre) et lasqlite3_errmsg
sera de retour le laconique "out of memory" erreur.Un couple de d'autres, sans rapport avec les observations:
Vous devriez vraiment vérifier le code de retour de
sqlite3_prepare
ainsi:Dans mon expérience, beaucoup de problèmes de développement sont liées à SQL lui-même, quelque chose qui est identifié par vérifier le code de retour de la
sqlite3_prepare_v2
déclaration.Vous ne devrait vraiment pas être la construction de votre instruction SQL dans un
NSString
. Vous vous ouvrez à des attaques par injection SQL ou, compte tenu de la plus bénigne de la situation, juste une erreur SQL si le nom de quelqu'un a un guillemet, par exempleThe "Destroyer"
. Vous devriez être en utilisant?
des espaces réservés et ensuite utilisersqlite3_bind_xxx
fonctions de lier les valeurs. Quelque chose comme:Vous pouvez ensuite appeler cela de la sorte:
Comme vous pouvez le voir, que vous commencez à écrire le code là où vous êtes correctement la vérification de chaque valeur de retour, la liaison de chaque variable, etc., votre SQLite code de poilu terriblement vite. Je vous suggère de vous contempler en regardant FMDB. C'est une belle, mince wrapper autour de l'SQLite fonctions, ce qui simplifie grandement l'exercice de l'écriture SQLite code en Objective-C.
Vous n'êtes pas de vérifier la valeur de la
sqlite3_prepare_v2
déclaration. Si ce n'est pasSQLITE_OK
puis, il y a un problème.Aussi, le fichier de base de données existe déjà? Si non, vous devez le créer ou de le charger à partir de la liasse.