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.
 
+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
     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
 Samuel Chen
 Daniel Dickison
+Peter Carr
 
 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