IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SQLite Discussion :

SQLITE_ERROR avec une requète simple en C++ sous Xcode avec Cocos2D-X


Sujet :

SQLite

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2012
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 4
    Par défaut SQLITE_ERROR avec une requète simple en C++ sous Xcode avec Cocos2D-X
    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)

  2. #2
    Modérateur
    Avatar de al1_24
    Homme Profil pro
    Retraité
    Inscrit en
    Mai 2002
    Messages
    9 133
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Retraité
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 9 133
    Par défaut
    As-tu vérifié si en passant la requête directement à SQLite, sans passer par ton ton programme, celle-ci s'exécutait correctement ?
    Par ailleurs, il n'est pas plus compliqué de détailler la liste des colonnes à retourner plutôt qu'utiliser une * qui pourrait retourner autre chose qu'attendu si tu changes la structure de ta table.
    Modérateur Langage SQL
    Règles du forum Langage SQL à lire par tous, N'hésitez pas à consulter les cours SQL
    N'oubliez pas le bouton et pensez aux balises
    [code]
    Si une réponse vous a aidé à résoudre votre problème, n'oubliez pas de voter pour elle en cliquant sur
    Aide-toi et le forum t'aidera : Un problème exposé sans mentionner les tentatives de résolution infructueuses peut laisser supposer que le posteur attend qu'on fasse son travail à sa place... et ne donne pas envie d'y répondre.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2012
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 4
    Par défaut
    Effectivement, j'ai tenté de lancer directement la requête avec SQLite (c'est que je voulais dire en écrivant "Je me suis connecté à la base via le terminal et j'ai pu y accéder tout à fait normalement.") et ma requête m'affiche bien le résultat attendu (c'est à dire toute la table, salement).

    C'est noté pour les noms des colonnes, je modifie ça de ce pas.

    Quoi qu'il en soit, je trouve bien étrange que la requête marche en passant par le terminal et échoue lamentablement via mon code. A noter que j'ai testé sous Android et sous iPhone et que le résultat est le même (c'est à dire : pas de résultat).

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2012
    Messages
    4
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 4
    Par défaut
    J'ai un début de piste : si je mets un nom d'une base qui n'existe pas, il m'affiche "base opened" quand même. Je pense que comme avec le terminal, quand la base n'existe pas, elle les crée, comme le laisse entendre ce que l'on peut lire sur le site de SQLite :

    The sqlite3_open() routine returns an integer error code rather than a pointer to the sqlite3 structure as the version 2 interface did. The difference between sqlite3_open() and sqlite3_open16() is that sqlite3_open16() takes UTF-16 (in host native byte order) for the name of the database file. If a new database file needs to be created, then sqlite3_open16() sets the internal text representation to UTF-16 whereas sqlite3_open() sets the text representation to UTF-8.
    Supposition : lorsque je fais mon open, il ne va pas chercher où je voudrais qu'il cherche et du coup il crée la base. Donc il faut que je trouve où il va chercher la base.

    EDIT > Quand je lance la version ObjC et regarde la valeur du NSString correspondant au chemin de la base dans le debugger, je trouve : /Users/monnom/Library/Application Support/iPhone Simulator/5.0/Applications/[plein de chiffres et de lettres]

    Donc ça confirme ce que je pensais : je ne vais pas chercher au bon endroit. Le problème n'est pas sur le SQLite mais plus sur le côté iPhone/Androïd apparemment. C'est la partie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:@"baseTestSilly" 
                ofType:@"sqlite3"];
    qu'il faut que j'arrive à reproduire via mon C++ et ce de manière portable...

    EDIT2 > Le problème est résolu du côté iPhone. C'est bien un problème de chemin. Il faut utiliser CCFileUtils::fullPathFromRelativePath :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    QuestionDatabase::QuestionDatabase()
    {
        if (sqlite3_open(cocos2d::CCFileUtils::fullPathFromRelativePath("baseTestSilly.sqlite3"), &database) != SQLITE_OK)
        {
            printf("Failed to open database");
        }
        else printf("Database opened");
    }

    Il reste toujours un problème côté Androïd, cependant.

    EDIT 3 > JE passe la question dans la section Androïd donc, je pense que c'est plus pertinent.

Discussions similaires

  1. Réponses: 3
    Dernier message: 25/10/2013, 08h46
  2. Réponses: 1
    Dernier message: 31/05/2011, 17h58
  3. [Web Service] Expiration d'une requête simple avec Amazon Web Services
    Par cyberlp dans le forum Bibliothèques et frameworks
    Réponses: 3
    Dernier message: 12/11/2010, 15h50
  4. Réponses: 2
    Dernier message: 18/11/2007, 20h17
  5. problème avec une requête imbriquée
    Par jaimepasteevy dans le forum Langage SQL
    Réponses: 13
    Dernier message: 05/12/2003, 10h29

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo