unable to open database - iphone

I am using below code for inserting data in the database. and i am inserting aprox 15000 records but after 245 records it throws the error "Unable to open database"
+(void)addGeoRegions:(const char *)query geoId:(int)geoId geoFatherId:(int)geoFatherId geoName:(NSString *)geoName
geoTypeRegionId:(NSString *)geoTypeRegionId geoZone:(int)geoZone
{
sqlite3_stmt *dataRows = nil;
#try {
if(sqlite3_open([[self getDBPath] UTF8String],&PatientDatabase) == SQLITE_OK)
{
if (sqlite3_prepare_v2(PatientDatabase, query, -1, &dataRows, NULL)!=SQLITE_OK)
{
NSAssert1(0,#"error while preparing %s",sqlite3_errmsg(PatientDatabase));
}
sqlite3_bind_int(dataRows, 1, geoId);
sqlite3_bind_int(dataRows, 2, geoFatherId);
sqlite3_bind_text(dataRows, 3, [geoName UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_text(dataRows, 4, [geoTypeRegionId UTF8String], -1, SQLITE_TRANSIENT);
sqlite3_bind_int(dataRows, 5, geoZone);
if (SQLITE_DONE!=sqlite3_step(dataRows))
{
char *err;
err=(char *) sqlite3_errmsg(PatientDatabase);
if (err)
sqlite3_free(err);
NSAssert1(0,#"error while inserting geo regions. %s",sqlite3_errmsg(PatientDatabase));
}
}
}
#catch (NSException * e) {
}
#finally
{
sqlite3_close(PatientDatabase);
sqlite3_finalize(dataRows);
PatientDatabase=nil;
}
}
so please can any one suggest why this problem is occur.

Firstly, think about Mark's answer, you'll get better performance if you open the database once and close it once.
Anyway, that was a suggestion for a design improvement. What is actually wrong in your code is the finally block:
#finally
{
sqlite3_close(PatientDatabase); // will fail!
sqlite3_finalize(dataRows);
PatientDatabase=nil;
}
Here is the relevant line from the sqlite3_close() docs.
Applications must finalize all prepared statements and close all BLOB handles associated with the sqlite3 object prior to attempting to close the object. If sqlite3_close() is called on a database connection that still has outstanding prepared statements or BLOB handles, then it returns SQLITE_BUSY.
You need to run the finalize before closing the database. As things stand, the close call fails and you end up with 245 open database handles.
So, reverse the order of the two statements and check your return codes for failure.
By the way, NSAssert is not an appropriate way to report errors. Throw an exception or return an error, or just log it. NSAssert is designed to catch programming errors. It won't even be compiled into your release code.

Sqlite has much better performance "in transation" on inserts without transaction. I particularly, massive use transaction processes, or failure comes randomly at some point with error "unable to open database file"

You are opening the database on each call it would take less resource to open it once then add all the rows before closing it. In theory what you are doing should work but it is not a way I would even start using.

Related

SQLCIPHER sqlite encrypted iphone ios converting un-encrypted database to encrypted database

I know that there are a few postings on this, but just want to make sure there is something that I am not missing / current.
Using sqlcipher, with an unencrypted database, want to encrypt it. Encrypting a new database is working fine.
Am trying the sqlcipher rekey with an existing database seems NOT to be working (Database remains unencrypted).
[fmdb open];
NSString *sel = #"SELECT count(*) FROM sqlite_master";
FMResultSet *fmr = [self executeQuery : fmdb : sel];
if ( [fmr next] ) // unencrypted
{
NSLog(#"Encrypting");
fmdb.key = #"";
[fmdb rekey : #"somekey"];
}
Otherwise will have to use one of the other PRAGMA methods, etc.
Does rekey only work with databases that are already encrypted?
This is using the FMDatabase Framework, but under the hood in the framework it is doing ...
- (BOOL)rekey:(NSString*)key {
#ifdef SQLITE_HAS_CODEC
if (!key) {
return NO;
}
int rc = sqlite3_rekey(db, [key UTF8String], (int)strlen([key UTF8String]));
if (rc != SQLITE_OK) {
NSLog(#"error on rekey: %d", rc);
NSLog(#"%#", [self lastErrorMessage]);
}
return (rc == SQLITE_OK);
#else
return NO;
#endif
}
It does run though the sqlite3_rekey, no errors, but database does not get encrypted.
All of the previous comments on this question are incorrect. You cannot use rekey to encrypt a plaintext database. Rekey is only to be used to change the encryption key on an encrypted database.
The correct way to encrypt a plaintext database is attach and export - see examples here http://sqlcipher.net/sqlcipher-api/#sqlcipher_export
The trick was that when the database is used to check for encryption (next time opening app) when it is already encrypted, but do not use a key to do a select, this will fail, but then the database will HAVE to be closed and reopened again with the key.

Setting sqlite config SQLITE_CONFIG_SERIALIZED returns SQLITE_MISUSE on iOS 5

With the release of iOS 5 we are getting more and more errors when setting the serialized option for the sqlite database (so its save to be used for multithreading). We are getting SQLITE_MISUSE error code on sqlite3_config. Has someone noticed this odd behavior? And does someone know how I can fix this? It works perfectly fine on previous iOS versions.
here is the code:
- (sqlite3 *)getNewDBConnection {
NSLog(#"sqlite3 lib version: %s", sqlite3_libversion());
//sqlite3_config() has to be called before any sqlite3_open calls.
if (sqlite3_threadsafe() > 0) {
int retCode = sqlite3_config(SQLITE_CONFIG_SERIALIZED);
if (retCode == SQLITE_OK) {
NSLog(#"Can now use sqlite on multiple threads, using the same connection");
} else {
NSLog(#"setting sqlite thread safe mode to serialized failed!!! return code: %d", retCode);
}
} else {
NSLog(#"Your SQLite database is not compiled to be threadsafe.");
}
sqlite3 *newDBconnection;
// Open the database
if (sqlite3_open([[self getDatabaseFilePath] UTF8String], &newDBconnection) == SQLITE_OK) {
NSLog(#"Database Successfully Opened :)");
} else {
sqlite3_close(newDBconnection);
NSLog(#"Error in opening database :(");
}
return newDBconnection;
}
and this is the output:
sqlite3 lib version: 3.7.7
setting sqlite thread safe mode to serialized failed!!! return code: 21
Database Successfully Opened :)
I struggled long and hard with this as well and finally got the solution.
As #enobufs said, sqlite3_config() needs to be called before sqlite3_initialize(). However, the OS might initialize SQLite for us so I also do a sqlite3_shutdown() before the sqlite3_config().
sqlite3_shutdown()
sqlite3_config()
sqlite3_initialize().
Then its also necessary to use the same connection for every query as it is the access to the database connection that gets serialized. As described here http://www.sqlite.org/capi3ref.html#sqliteconfigserialized
So I create a connection as soon as the app starts up and the pass that connection to every class that needs it.
Is the sqlite3_config() called before sqlite3_initialize()? The function returns SQLITE_MISUSE if called after sqlite3_initialize() and before sqlite3_shutdown(). See http://www.sqlite.org/c3ref/config.html for more details.

Why would alSourceUnqueueBuffers fail with INVALID_OPERATION

Here's the code:
ALint cProcessedBuffers = 0;
ALenum alError = AL_NO_ERROR;
alGetSourcei(m_OpenALSourceId, AL_BUFFERS_PROCESSED, &cProcessedBuffers);
if((alError = alGetError()) != AL_NO_ERROR)
{
throw "AudioClip::ProcessPlayedBuffers - error returned from alGetSroucei()";
}
alError = AL_NO_ERROR;
if (cProcessedBuffers > 0)
{
alSourceUnqueueBuffers(m_OpenALSourceId, cProcessedBuffers, arrBuffers);
if((alError = alGetError()) != AL_NO_ERROR)
{
throw "AudioClip::ProcessPlayedBuffers - error returned from alSourceUnqueueBuffers()";
}
}
The call to alGetSourcei returns with cProcessedBuffers > 0, but the following call to alSourceUnqueueBuffers fails with an INVALID_OPERATION. This in an erratic error that does not always occur. The program containing this sample code is a single-threaded app running in a tight loop (typically would be sync'ed with a display loop, but in this case I'm not using a timed callback of any sort).
Try alSourceStop(m_OpenALSourceId) first.
Then alUnqueueBuffers(), and after that, Restart playing by alSourcePlay(m_OpenALSourceId).
I solved the same problem by this way. But I don't know why have to do so in
Mentioned in this SO thread,
If you have AL_LOOPING enabled on a streaming source the unqueue operation will fail.
The looping flag has some sort of lock on the buffers when enabled. The answer by #MyMiracle hints at this as well, stopping the sound releases that hold, but it's not necessary..
AL_LOOPING is not meant to be set on a streaming source, as you manage the source data in the queue. Keep queuing, it will keep playing. Queue from the beginning of the data, it will loop.

iphone - try, catch question

I have a method that has several parts that can throw an exception. If one of these parts fail, I would like the cleaning method to run. I am thinking about using the try/catch directive.
My question is: will I have to use one directive for every line of code that can throw an exception or can I simply include the whole method in a block like this?
#try {
[self doStuff];
// doStuff has several passages that could throw an exception
}
#catch (NSException * e) {
[self cleanTheWholeThing];
}
In this case it is not important to me which line generated the problem. I just need the method to run successfully or do other stuff in case it fails.
thanks
If you can, avoid exceptions. Even Apple recommends to avoid them:
Instead of exceptions, error objects (NSError) and the Cocoa error-delivery mechanism are the recommended way to communicate expected errors in Cocoa applications.
See also their Error Handling Programming Guide (it's marked as being Mac related but is equally valid for iPhone, the same concepts apply).
The reasons for avoiding exceptions are that I know of are:
They are slower than reporting via NSError and an out-pointer.
They can result in memory leaks if you aren't very careful. Some memory leaks due to exceptions cannot be avoided at all (in non-GC environments).
You might forget to catch them, and then your app crashes.
In general, exceptions in Objective-C are used for really exceptional problems that are often unrecoverable. They are almost never used in area where you expect something can go wrong (like network communication; the NSURLConnection methods do not throw exceptions for this reason but export an NSError). This may be different from other languages where exceptions are used more often. In the projects I've been working on I had only once the need to catch and handle an exception (can't remember which, though).
Instead, you should do something like this:
// Returns YES when successful.
- (BOOL)doSomething:(NSError **)outError
{
// ...
if (someErrorOccurred) {
if (outError) {
outError = [NSError
errorWithDomain:#"MyErrorDomain"
code:123
userInfo:nil
];
// Or maybe even use your own NSError subclass
return NO;
}
}
// ...
// Operation was successful.
return YES;
}
You can certainly have multiple lines in your try block. Example:
#try {
if (managedObjectContext == nil) {
actionMessage = #"accessing user recipe library";
[self initCoreDataStack];
}
actionMessage = #"finding recipes";
recipes = [self recipesMatchingSearchParameters];
actionMessage = #"generating recipe summaries";
summaries = [self summariesFromRecipes:recipes];
}
#catch (NSException *exception) {
NSMutableDictionary *errorDict = [NSMutableDictionary dictionary];
[errorDict setObject:[NSString stringWithFormat:#"Error %#: %#", actionMessage, [exception reason]] forKey:OSAScriptErrorMessage];
[errorDict setObject:[NSNumber numberWithInt:errOSAGeneralError] forKey:OSAScriptErrorNumber];
*errorInfo = errorDict;
return input;
} #catch (OtherException * e) {
....
} #finally {
// Any clean up can happen here.
// Finally will be called if an exception is thrown or not.
}
And a link to practical use of exceptions:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
Its completely alright to enclose the method call with try-catch block.
If you don't care which line caused the exception you can enclose the entire function in a try/catch block.
For example, assume that f1(), f2() or f3() can throw an exception in this code:
try {
f1();
f2();
f3();
}
catch( ... ) {
...either f1, f2 or f3 threw an exception - don't know which
}
You can include the whole method body in your try block.
In your catch part you can have multiple catch blocks to handle different types of exceptions:
#catch (NSException * e) {
....
}
#catch (OtherException * e) {
....
}
#finally {
NSLog(#"finally");
}
so you could also discern exactly which line failed based on the specific exception raised, if you ever need it.
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html
You can include the whole method body in your try block.

Invalid attempt to call FieldCount when reader is closed

The error above occurs when I try to do a dataReader.Read on the data recieved from the database. I know there are two rows in there so it isnt because no data actually exists.
Could it be the CommandBehavior.CloseConnection, causing the problem? I was told you had to do this right after a ExecuteReader? Is this correct?
try
{
_connection.Open();
using (_connection)
{
SqlCommand command = new SqlCommand("SELECT * FROM Structure", _connection);
SqlDataReader dataReader = command.ExecuteReader(CommandBehavior.CloseConnection);
if (dataReader == null) return null;
var newData = new List<Structure>();
while (dataReader.Read())
{
var entity = new Structure
{
Id = (int)dataReader["StructureID"],
Path = (string)dataReader["Path"],
PathLevel = (string)dataReader["PathLevel"],
Description = (string)dataReader["Description"]
};
newData.Add(entity);
}
dataReader.Close();
return newData;
}
}
catch (SqlException ex)
{
AddError(new ErrorModel("An SqlException error has occured whilst trying to return descendants", ErrorHelper.ErrorTypes.Critical, ex));
return null;
}
catch (Exception ex)
{
AddError(new ErrorModel("An error has occured whilst trying to return descendants", ErrorHelper.ErrorTypes.Critical, ex));
return null;
}
finally
{
_connection.Close();
}
}
Thanks in advance for any help.
Clare
When you use the Using in C#, after the last } from the using, the Connection automatically close, thats why you get the fieldcount to be closed when u try to read him, as that is impossible, because u want those datas, read then before close the using, or u can open and close manually the connection, by not using the (using)
Your code, as displayed is fine. I've taken it into a test project, and it works. It's not immediately clear why you get this message with the code shown above. Here are some debugging tips/suggestions. I hope they're valuable for you.
Create a breakpoint on the while (dataReader.Read()). Before it enters its codeblock, enter this in your Immediate or Watch Window: dataReader.HasRows. That should evaluate to true.
While stopped on that Read(), open your Locals window to inspect all the properties of dataReader. Ensure that the FieldCount is what you expect from your SELECT statement.
When stepping into this Read() iteration, does a student object get created at all? What's the value of dataReader["StructureID"] and all others in the Immediate Window?
It's not the CommandBehavior.CloseConnection causing the problem. That simply tells the connection to also close itself when you close the datareader.
When I got that error, it happened to be a command timeout problem (I was reading some large binary data). As a first attempt, I increased the command timeout (not the connection timeout!) and the problem was solved.
Note: while attempting to find out the problem, I tried to listen to the (Sql)connection's StateChanged event, but it turned out that the connection never fall in a "broken" state.
Same problem here. Tested all the above solutions
increase command timeout
close the connection after read
Here's the code
1 objCmd.Connection.Open()
2 objCmd.CommandTimeout = 3000
3 Dim objReader As OleDbDataReader = objCmd.ExecuteReader()
4 repeater.DataSource = objReader
5 CType(repeater, Control).DataBind()
6 objReader.Close()
7 objCmd.Connection.Dispose()
Moreover, at line 4 objReader has Closed = False
I got this exception while using the VS.NET debugger and trying to examine some IQueryable results. Bad decision because the IQueryable resulted in a large table scan. Stopping and restarting the debugger and NOT trying to preview this particular IQueryable was the workaround.