2013-08-15 4 views
1

저는 데이터베이스에 최고 점수를 저장하려고 노력 해왔고 지난 주 동안 실패했습니다. 왜 작동하지 않는지 전혀 알지 못합니다. "준비 문과 관련된 문제"를 계속 받고 정보를 데이터베이스에 삽입하는 것을 거부합니다. 데이터베이스 관리자와 함께 SQL 문에 오타가 없는지 확인하고 관리자가 쿼리를 실행할 때 제대로 작동합니다. 문제가있는 아이폰 일뿐입니다. 누구든지 빨리 살펴보고 잘못 된 것을보고 알려 주면 정말 감사하겠습니다. 여기 sqlite_prepare_v2가 SQLITE_OK를 반환하지 않습니다

- (NSMutableArray *) saveLocal { 
    NSLog(@"save local database"); 
    @try { 
     [self checkDB]; 
     sqlite3_stmt *sqlStatement2; 


     NSString *sqlS = [NSString stringWithFormat:@"INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (%i,%i,\"%@\",%i,%i,%i,%i)",[[MySingleton sharedMySingleton] goDifficulty],[[MySingleton sharedMySingleton] goScore],_player, [[MySingleton sharedMySingleton] goPuzzles], [[MySingleton sharedMySingleton] goMultiplier], [[MySingleton sharedMySingleton] goOneshots], [[MySingleton sharedMySingleton] goHints]]; 
     NSLog(@"%@",sqlS); 
     const char *sql = [sqlS UTF8String]; 


     if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK) 
     { 
      sqlite3_step(sqlStatement2); 
      sqlite3_reset(sqlStatement2); 
      sqlite3_finalize(sqlStatement2); 
      NSLog(@"save complete"); 
     } else { 
      NSLog(@"Problem with prepare statement"); 
     } 
     sqlite3_close(localHighscore); 
    }@catch (NSException *exception) { 
     NSLog(@"An exception occured: %@", [exception reason]); 
    }@finally{ 
     NSLog(@"DB Loaded!"); 
    } 
} 

데이터베이스가 존재하는지 확인하고 그렇지

- (void)checkDB { 
    NSString *docsDir; 
    NSArray *dirPaths; 

    // Get the documents directory 
    dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 

    docsDir = [dirPaths objectAtIndex:0]; 

    // Build the path to the database file 
    databasePath = [[NSString alloc] initWithString: [docsDir stringByAppendingPathComponent: @"localHighscore.sqlite"]]; 

    NSFileManager *filemgr = [NSFileManager defaultManager];  
    if ([filemgr fileExistsAtPath: databasePath ] == NO) 
    { 
    const char *dbpath = [databasePath UTF8String]; 
     NSLog(@"file was not found"); 
     if (sqlite3_open(dbpath, &localHighscore) == SQLITE_OK) 
     { 
      NSLog(@"db open"); 
      char *errMsg; 
      const char *sql_stmt = "CREATE TABLE IF NOT EXISTS localHighscore(pk INTEGER PRIMARY KEY AUTOINCREMENT, difficulty TINYINT, score MEDIUMINT, uname VARCHAR(255), puzzles TINYINT, multiplier TINYINT, oneshots TINYINT, hints TINYINT)"; 

      if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) 
      { 
       NSLog(@"Failed to create table"); 
      } 
      sqlite3_close(localHighscore);    
     } else { 
      NSLog(@"Failed to open/create database"); 
     } 
    } 
    [filemgr release]; 
} 

감사를 수행하면 도움을 사전에 하나를 생성 CHECKDB 방법입니다!

답변

3

생각을 몇 :

  1. 데이터베이스를 사용하기 전에 sqlite3_open를 호출 할 나타나지 않습니다.

  2. 오류가 발생할 때마다 sqlite3_errmsg을 확인해야합니다.

    if (sqlite3_exec(localHighscore, sql_stmt, NULL, NULL, &errMsg) != SQLITE_OK) 
    { 
        NSLog(@"Failed to create table: %s", sqlite3_errmsg(localHighscore)); 
    } 
    
  3. 문제에 아마 관련이없는

    ,하지만 당신은 일반적으로 (당신이 어떤 텍스트 필드가 적어도 경우) stringWithFormat를 사용하여 SQL 문을 작성하지 않아야합니다. SQL에 ? 자리 표시자를 사용하고 sqlite3_bind_xxx 함수를 사용하십시오.

    const char *sql = "INSERT INTO localHighscore (difficulty, score, uname, puzzles, multiplier, oneshots, hints) VALUES (?,?,?,?,?,?,?)"; 
    
    if(sqlite3_prepare_v2(localHighscore, sql, -1, &sqlStatement2, NULL) == SQLITE_OK) 
    { 
        if (sqlite3_bind_int(sqlStatement2, 1, [[MySingleton sharedMySingleton] goDifficulty]) != SQLITE_OK) { 
         NSLog(@"bind 1 failed: %s", sqlite3_errmsg(localHighscore)); 
        } 
    
        if (sqlite3_bind_int(sqlStatement2, 2, [[MySingleton sharedMySingleton] goScore]) != SQLITE_OK) { 
         NSLog(@"bind 2 failed: %s", sqlite3_errmsg(localHighscore)); 
        } 
    
        if (sqlite3_bind_text(sqlStatement2, 3, [_player UTF8String], -1, NULL) != SQLITE_OK) { 
         NSLog(@"bind 3 failed: %s", sqlite3_errmsg(localHighscore)); 
        } 
    
        // repeat this bind process for each variable 
    
        if (sqlite3_step(sqlStatement2) != SQLITE_DONE) { 
         NSLog(@"step failed: %s", sqlite3_errmsg(localHighscore)); 
        } 
    
        // reset not needed (doesn't hurt, but not needed unless you're going to re-use it 
        // sqlite3_reset(sqlStatement2); 
    
        sqlite3_finalize(sqlStatement2); 
        NSLog(@"save complete"); 
    } else { 
        NSLog(@"Problem with prepare statement: %s", sqlite3_errmsg(localHighscore)); 
    } 
    sqlite3_close(localHighscore); 
    

    이 구문은 다루기 찾아내는 경우에, 어쩌면 당신의 SQL의 상호 작용을 단순화 FMDB을 사용하는 것이 좋습니다. 그러나 stringWithFormat을 SQL에 매우주의하십시오 (삽입 된 문자열에 인용 부호가있는 경우 이론적으로는 sqlite3_prepare이 실패하고 응용 프로그램이 SQL 삽입 공격 등에 노출됩니다).

  4. 제쳐두고, 자신이 소유하지 않으므로 [filemgr release]을 사용하면 안됩니다.

+0

오 와우 나는 바보 같았다! 자세한 답변을 해주셔서 대단히 감사합니다. 그것은 sqlite_open ... 그리고 errmsg는 지금 많은 시간을 절약 할 것입니다! 다시 한 번 감사드립니다! –

+0

'sqlite_errmsg'가 시간을 절약했습니다. 말 그대로, 아마도. 감사합니다. D : 테이블을 만들 때 "Tickable"열의 이름이 "Tickableinteger"로 지정되었으므로 공간을 놓쳤습니다!) – EvilGeniusJamie

관련 문제