Browse Source

Added a new addition which can be used for reading and writing on disk databases to in memory databases.

ccgus 13 years ago
parent
commit
bbca6425f3

+ 3 - 0
CHANGES_AND_TODO_LIST.txt

@@ -3,6 +3,9 @@ Zip, nada, zilch.  Got any ideas?
 
 
 If you would like to contribute some code- awesome!  I just ask that you make it conform to the coding conventions already set in here, and to add a couple of tests for your new code to fmdb.m.  And of course, the code should be of general use to more than just a couple of folks.  Send your patches to gus@flyingmeat.com.
 If you would like to contribute some code- awesome!  I just ask that you make it conform to the coding conventions already set in here, and to add a couple of tests for your new code to fmdb.m.  And of course, the code should be of general use to more than just a couple of folks.  Send your patches to gus@flyingmeat.com.
 
 
+2013.02.05
+    Added an "extra" folder which contains additional things which might be useful for programmers, but which I don't think should be part of the standard classes.  At this time- there's only a single category in there which will load and save an on disk database to an in memory database.  Thanks to Peter Carr who provided these additions!  
+
 2013.01.31
 2013.01.31
     Lazy init of columnNameToIndexMap in FMResultSet, and you are now able to use it before asking for any rows first.  Thanks to Daniel Dickison for the patch!
     Lazy init of columnNameToIndexMap in FMResultSet, and you are now able to use it before asking for any rows first.  Thanks to Daniel Dickison for the patch!
 
 

+ 1 - 0
CONTRIBUTORS.txt

@@ -35,5 +35,6 @@ Geoffrey Foster
 Robert Ryan
 Robert Ryan
 Samuel Chen
 Samuel Chen
 Daniel Dickison
 Daniel Dickison
+Peter Carr
 
 
 Aaaaannnd, Gus Mueller (that's me!)
 Aaaaannnd, Gus Mueller (that's me!)

+ 26 - 0
extra/FMDatabase+InMemoryOnDiskIO.h

@@ -0,0 +1,26 @@
+//
+//  FMDatabase+InMemoryOnDiskIO.h
+//  FMDB
+//
+//  Created by Peter Carr on 6/12/12.
+//
+//  I find there is a massive performance hit using an "on-disk" representation when
+//  constantly reading from or writing to the DB.  If your machine has sufficient memory, you
+//  should get a significant performance boost using an "in-memory" representation.  The FMDB
+//  warpper does not contain methods to load an "on-disk" representation into memory and
+//  similarly save an "in-memory" representation to disk.  However, SQLite3 has built-in 
+//  support for this functionality via its "Backup" API.  Here, we extend the FMBD wrapper
+//  to include this functionality.
+//
+//  http://www.sqlite.org/backup.html
+
+#import "FMDatabase.h"
+
+@interface FMDatabase (InMemoryOnDiskIO)
+
+// Loads an on-disk representation into memory.
+- (BOOL)readFromFile:(NSString*)filePath;
+
+// Saves an in-memory representation to disk
+- (BOOL)writeToFile:(NSString *)filePath;
+@end

+ 96 - 0
extra/FMDatabase+InMemoryOnDiskIO.m

@@ -0,0 +1,96 @@
+#import "FMDatabase+InMemoryOnDiskIO.h"
+
+// http://www.sqlite.org/backup.html
+static
+int loadOrSaveDb(sqlite3 *pInMemory, const char *zFilename, int isSave)
+{
+    int rc;                   /* Function return code */
+    sqlite3 *pFile;           /* Database connection opened on zFilename */
+    sqlite3_backup *pBackup;  /* Backup object used to copy data */
+    sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
+    sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */
+    
+    /* Open the database file identified by zFilename. Exit early if this fails
+     ** for any reason. */
+    rc = sqlite3_open(zFilename, &pFile);
+    if( rc==SQLITE_OK ){
+        
+        /* If this is a 'load' operation (isSave==0), then data is copied
+         ** from the database file just opened to database pInMemory. 
+         ** Otherwise, if this is a 'save' operation (isSave==1), then data
+         ** is copied from pInMemory to pFile.  Set the variables pFrom and
+         ** pTo accordingly. */
+        pFrom = (isSave ? pInMemory : pFile);
+        pTo   = (isSave ? pFile     : pInMemory);
+        
+        /* Set up the backup procedure to copy from the "main" database of 
+         ** connection pFile to the main database of connection pInMemory.
+         ** If something goes wrong, pBackup will be set to NULL and an error
+         ** code and  message left in connection pTo.
+         **
+         ** If the backup object is successfully created, call backup_step()
+         ** to copy data from pFile to pInMemory. Then call backup_finish()
+         ** to release resources associated with the pBackup object.  If an
+         ** error occurred, then  an error code and message will be left in
+         ** connection pTo. If no error occurred, then the error code belonging
+         ** to pTo is set to SQLITE_OK.
+         */
+        pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
+        if( pBackup ){
+            (void)sqlite3_backup_step(pBackup, -1);
+            (void)sqlite3_backup_finish(pBackup);
+        }
+        rc = sqlite3_errcode(pTo);
+    }
+    
+    /* Close the database connection opened on database file zFilename
+     ** and return the result of this function. */
+    (void)sqlite3_close(pFile);
+    return rc;
+}
+
+
+
+@implementation FMDatabase (InMemoryOnDiskIO)
+
+- (BOOL)readFromFile:(NSString*)filePath
+{
+    // only attempt to load an on-disk representation for an in-memory database
+    if ( self->_databasePath != nil ) 
+    {
+        NSLog(@"Database is not an in-memory representation." );
+        return NO;
+    }
+    
+    // and only if the database is open
+    if ( self->_db == nil ) 
+    {
+        NSLog(@"Invalid database connection." );
+        return NO;
+    }
+    
+    return ( SQLITE_OK == loadOrSaveDb( self->_db, [filePath fileSystemRepresentation], false ) );
+
+}
+
+- (BOOL)writeToFile:(NSString *)filePath
+{
+    // only attempt to save an on-disk representation for an in-memory database
+    if ( self->_databasePath != nil )
+    {
+        NSLog(@"Database is not an in-memory representation." );
+        return NO;
+    }
+    
+    // and only if the database is open
+    if ( self->_db == nil ) 
+    {
+        NSLog(@"Invalid database connection." );
+        return NO;
+    }
+    
+    // save the in-memory representation    
+    return ( SQLITE_OK == loadOrSaveDb( self->_db, [filePath fileSystemRepresentation], true ) );
+}
+
+@end