SparkyNZ
SparkyNZ

Reputation: 6676

SQLite Query containing Path failing on iPhone

I have tried both a prepared statement and a regular statement to retrieve a record from my table using a long iPhone simulator path.

I simply cannot get a SELECT statement to work which uses field Path in the WHERE statement. If I remove the WHERE statement, it returns the record.

e.g.

Last Added[/Users/admin/Library/Developer/CoreSimulator/Devices/1546523B-D9E4-45F6-9ACA-ADA5CF73DFE4/data/Containers/Data/Application/9187662E-16F3-4573-B486-256BDA00CBD1/Documents/wf_mages-3.lha]

SQL[SELECT ID FROM Tune  WHERE Path="/Users/admin/Library/Developer/CoreSimulator/Devices/1546523B-D9E4-45F6-9ACA-ADA5CF73DFE4/data/Containers/Data/Application/9187662E-16F3-4573-B486-256BDA00CBD1/Documents/wf_mages-3.lha"]

I have tried both double and single quotes in the query. I have even tried the same query in SQLiteBrowser and it works fine.

SELECT ID FROM Tune WHERE Path LIKE '%mages%' works fine.

Is the problem with the forward slashes or the size of the path value? Do forward slashes need to be escaped somehow?

The only other post I could find about forward slashes recommended prepared statements being used but that's what I started with originally and they wouldn't work. Look-ups work fine on any other fields in my tables - just not paths.

int GetTuneIDWithPath( char *pszPath )
{
  // TEST
  char   txTmp   [ 1024 ];

  sprintf( g_txSQL, "SELECT %s", fldTune_ID );

  sprintf( txTmp, " FROM %s ", tbTune );
  strcat( g_txSQL, txTmp );

  //sprintf( txTmp, " WHERE %s=\"%s\"", fldTune_Path, pszPath );
  //strcat( g_txSQL, txTmp );

//  sprintf( txTmp, " WHERE %s='%s'", fldTune_Path, pszPath );
  //strcat( g_txSQL, txTmp );

  //sprintf( txTmp, " WHERE %s LIKE '%%mages%%'", fldTune_Path );
  //strcat( g_txSQL, txTmp );

  LogDebugf( "SQL[%s]", g_txSQL );

  char  *zErrMsg = 0;
  char **pszResult;
  int    nRows;
  int    nCols;
  int    rc;

  rc = sqlite3_get_table_wrapper( g_MainDB,
                                 g_txSQL,
                                 &pszResult,
                                 &nRows,
                                 &nCols,
                                 &zErrMsg );

  if( nRows != 1 )
  {
    LogDebugf( "FAILED nRows: %d", nRows );
    return FALSE;
  }

  // First row is field names, so start at 1
  int nCol = 0;
  int nID = Safe_atoi(    pszResult[ nCols + nCol ] );  nCol ++;

  LogDebugf( "PDS> nID: %d Find[%s]", nID, pszPath );  
  return nID;
}

Prior to this I did try using prepared statements like I do for other queries:

  char   txTmp   [ 1024 ];

  sprintf( g_txSQL, "SELECT %s", fldTune_ID );    
  sprintf( txTmp, " FROM %s WHERE %s=?", tbTune, fldTune_Path );
  strcat( g_txSQL, txTmp );

  sqlite3_stmt *stmt = NULL;  
  sqlite3_prepare( g_MainDB, g_txSQL, -1, &stmt, NULL );
  sqlite3_reset( stmt );
  sqlite3_bind_text( stmt,  1, pszPath, strlen( pszPath ), SQLITE_STATIC );

  rc = sqlite3_step( stmt );

  if( rc != SQLITE_ROW ) 
  {
    LogDebugf( "PDS> Lookup failed [%s] rc: %d", pszPath, rc );
    return FALSE;
  }

  int nID = sqlite3_column_int( stmt, 0 );

  LogDebugf( "PDS> nID: %d Find[%s]", nID, pszPath );

Upvotes: 1

Views: 35

Answers (1)

trojanfoe
trojanfoe

Reputation: 122458

You need to ignore the actual location of the file and only record and search for files within the app documents directory, so you need to store/search for 'wf_mages-3.lha' and not '/Users/admin/Library/Developer/CoreSimulator/Devices/1546523B-D9E4-45F6-9ACA-ADA5CF73DFE4/data/Containers/Data/Application/9187662E-16F3-4573-B486-256BDA00CBD1/Documents/wf_mages-3.lha'.

Only when actually reading/writing the file do you need to prepend the documents path, which you get via NSSearchPathForDirectoriesInDomains().

The reason for this is that the location will change during an app update and the documents directory contents will be migrated but the database rows will not, and you will have lost the connection between the two.

There should be no issue using '/' in the statement as it's not special as far as SQL is concerned, and so it should be possible to create a hierarchy within the documents folder without problem.

To comment on your code, I've never seen that method used before and I would advocate the more conventional sqlite3_prepare(), sqlite3_step(), and sqlite3_finalize() functions. Also, most crucially, you need to report any errors using sqlite3_errmsg(), otherwise you'll make no progress at all.

Upvotes: 2

Related Questions