Bonjour tout le monde.
Un petit problème.
Je développe actuellement un jeu de Quizz sur iPhone et Androïd via cocos2D-x. J'ai effectué l'installation de cocos2D-x grâce à un tuto pris sur le site de Ray Wenderlich.
J'ai une base de données SQLite appelée baseTestSilly.sqlite3 dans laquelle se trouve une table appelée tableFR qui contient mes questions. La dite base se trouve dans un dossier sharedRessource conçu comme proposé ici. Actuellement, j'ai un une application avec un bouton (qui tourne sur iPhone et Androïd, donc a priori les deux applis vont bien chercher les ressources aux bons endroits). Mon but est est de prendre une ligne (= une question) au hasard dans la table puis de l'afficher dans la console dès que j'appuie sur le bouton.
J'ai créé une classe QuestionFour qui est peu ou prou un container pour une question (des string pour la référence et le texte de la question, un vector<string> pour les réponses et un int pour le numéro de la bonne réponse).
J'ai une classe QuestionDatabase qui est une classe singleton qui est chargée d'ouvrir ma base de données et d'y accéder dont voici le code du fichier *.cpp
Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 #include "QuestionDatabase.h" //using namespace cocos2d; // -- Constructors and singleton stuffs -- // QuestionDatabase::QuestionDatabase() { if (sqlite3_open("baseTestSilly.sqlite3", &database) != SQLITE_OK) { printf("Failed to open database"); } else printf("Database opened"); } QuestionDatabase::~QuestionDatabase() { } QuestionDatabase * QuestionDatabase::getInstance() { if (instance == NULL) { instance = new QuestionDatabase(); } return instance; } void QuestionDatabase::killInstance() { if (instance != NULL) { sqlite3_close(database); delete instance; instance = NULL; } } QuestionDatabase * QuestionDatabase::instance = NULL; sqlite3 * QuestionDatabase::database = NULL; // -- Methods -- // QuestionFour * QuestionDatabase::getRandomQuestion() { string //query = "SELECT * FROM tableFR WHERE rowid = (abs(random()) % (select max(rowid)+1 from tableFR));"; //Random row query = "SELECT * FROM tableFR;"; sqlite3_stmt * statement; int debugVar = sqlite3_prepare_v2(database, query.c_str(), -1, &statement, NULL); if (debugVar == SQLITE_OK ) //if (sqlite3_prepare_v2(database, query.c_str(), -1, &statement, NULL) == SQLITE_OK ) { if (sqlite3_step(statement) == SQLITE_ROW) { string ref = (char *)sqlite3_column_text(statement, 0); string question = (char *)sqlite3_column_text(statement, 2); int correct = sqlite3_column_int(statement, 7); vector<string> answers; for (int i = 0; i < 4 ; i++) { answers[i] = (char*)sqlite3_column_text(statement, i+3); } sqlite3_finalize(statement); return new QuestionFour(ref, question, answers, correct); } } sqlite3_finalize(statement); return NULL; }
Pour afficher ma question random dans la console, je lance cette très simple fonction :
Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 void HelloWorld::buzzerTapped(CCObject* pSender) { QuestionFour * question = QuestionDatabase::getInstance()->getRandomQuestion(); if(question !=NULL) printf("%s",question->getQuestion().c_str()); }
(Je n'ai pas encore codé de code permettant d'afficher la question à l'écran, mais comme je n'arrive pas jusque là...)
Lorsque que j’appelle : QuestionDatabase::getInstance()->getRandomQuestion(), la console m'affiche bien "Database opened". Je suppose, vu mon code, que la base est bien ouverte.
Le problème, c'est que ma requête tombe à l'eau. Comme vous le voyez, j'ai tenté de faire la requête la plus simple possible mais debugVar est toujours égale à 1 (c-à-d.SQLITE_ERROR) et donc mon statement pointe sur NULL d'où impossibilité de créer une question. Je m'y perds complétement, surtout en sachant que j'avais produit ce code avec cocos2D la veille (avant de choisir une solution multiplateforme, j'avais créé un simple projet iOS) :
Code Objective-C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 - (id)init { if ((self = [super init])) { NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:@"baseTestSilly" ofType:@"sqlite3"]; if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) { NSLog(@"Failed to open database!"); } } return self; } - (void)dealloc { sqlite3_close(_database); [super dealloc]; } - (QuestionFourAns *) getRandomQuestion { NSString *query = @"SELECT * FROM tableFR WHERE rowid = (abs(random()) % (select max(rowid)+1 from tableTest));"; sqlite3_stmt *statement; if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) { if (sqlite3_step(statement) == SQLITE_ROW) { char * refChar = (char *) sqlite3_column_text(statement, 0); char * questionChar = (char *)sqlite3_column_text(statement, 2); int correct = (int)sqlite3_column_text(statement, 7); NSString *ref = [[NSString alloc] initWithUTF8String:refChar]; NSString *question = [[NSString alloc] initWithUTF8String:questionChar]; NSMutableArray * answers =[[NSMutableArray alloc] init]; for (int i = 3; i <7; i++) { char * ansChar = (char *)sqlite3_column_text(statement, i); NSString *ans = [[NSString alloc] initWithUTF8String:ansChar]; [answers addObject:ans]; [ans release]; } QuestionFourAns * retVal = [[QuestionFourAns alloc] initWithQuestion:question answ:answers crct:correct ref:ref]; NSLog(@"%@",ref); return retVal; } } else { NSLog(@"echec"); } sqlite3_finalize(statement); }
Code qui a la double particularité d'une part de ressembler vachement à mon code C++ et d'autre part de fonctionner parfaitement. Pour info, je m'étais basé sur ce tuto pour faire mon code ObjC.
La base utilisée pour mon projet cross-platform est un copié-collé de la base utilisée pour le projet en Objective-C. Je me suis connecté à la base via le terminal et j'ai pu y accéder tout à fait normalement. La table existe bien et n'est pas vide.
Et je ne comprends pas pourquoi ça ne marche pas. La seule différence entre le code ObjC et C++ que je vois est le "[query UTF8String]" qui est, je crois, inutile en C++. Je me trompe peut être. Je me suis demandé si le problème ne venait pas de la localisation de la base mais je me dis que si c'était le cas on n'arriverait pas du tout à l'ouvrir.
A noter que j'ai intégré sqlite3.h et sqlite3.c directement dans les sources dans mon projet, je ne sais pas trop si ça change quelque chose.
Si vous ne savez pas d'où vient l'erreur mais que vous avez une autre solution qui correspond aux contraintes de mon projet, c'est à dire accéder à une base créée à partir d'un fichier .csv pour en sortir une ligne au hasard ou une ligne au hasard parmi un sous ensemble de tuples (exemple : question de catégorie "cinéma") tout en garantissant la composante multiplateforme (Androïd et iPhone), je suis évidemment preneur.
Merci d'avance.
(J'espère que je ne me suis pas trompé de section, j'ai hésité entre C++ et SQLite)
Partager