SQLite3 error - iOS - ios

How can I figure out the error that SQLite3 is giving me when I make an SQL call:
int success = sqlite3_prepare_v2(database, sql, -1, &stmt, NULL);
if(success != SQLITE_OK) {
NSLog(#"create stmt failed %#",stmt);
}
All as I know is if it failed, but is there a way to get the actual error, or reason why it failed?

You can use the sqlite3_errmsg function. You need to pass in the db handle. The following code will log the error
NSLog(#"Error %s while preparing statement", sqlite3_errmsg(_dbHandle));

Sure, if success != SQLITE_OK, then it must be one of these error codes:
http://www.sqlite.org/c3ref/c_abort.html

Related

How to check for null in Dart?

I don't know what I am doing wrong. I thought that to check whether a variable x is not null in Dart, one could simply do x != null. But that does not work in this code below. And, it is not clear to me why. I would appreciate why it is not working.
void getUserAnswers() {
HttpRequest.getString(pathToUserAns).then((String data) {
print("data is: $data");
if (data != null) {
print("data is not null");
}
});
}
The above code gives the following output in the chromium console:
data is: null
data is not null
which does not seem to make sense.

SQLite query runs on SQLiteManager but not on iOS

Having an sqlite issue. The query runs fine on the firefox addon SQLiteManager. It does not run on iOS however. I get an error code of 1. The database gets connected to fine.
NSString *sqLiteDb = [[NSBundle mainBundle] pathForResource:#"featureDB"
ofType:#"sqlite3"];
if (sqlite3_open([sqLiteDb UTF8String], &_database) != SQLITE_OK) {
DLog(#"Failed to open database!");
} else {
DLog(#"Connected to db");
}
NSString *query = [NSString stringWithFormat:#"SELECT * FROM featureTable"];
sqlite3_stmt *statement;
NSLog(#"could not prepare statement: %s\n", sqlite3_errmsg(_database));
if (sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil) == SQLITE_OK) {
while (sqlite3_step(statement) == SQLITE_ROW) {
DLog(#"row");
int uniqueId = sqlite3_column_int(statement, 0);
}
sqlite3_finalize(statement);
DLog(#"sqliteStep");
} else {
DLog(#"statement Error %d", sqlite3_prepare_v2(_database, [query UTF8String], -1, &statement, nil));
}
The log for "row or sqliteStep" never fires.
Your else statement should not call sqlite3_prepare_v2 again, but rather should:
DLog(#"prepare error: %s", sqlite3_errmsg(_database));
What does this error message report?
Note: You already are logging sqlite3_errmsg before you call sqlite3_prepare_v2. Of course that's going to report no error, because no error could have possibly has taken place yet. Do this logging inside the else clause where you know sqlite3_prepare_v2 (a) has been called; but (b) didn't return SQLITE_OK. And don't call any SQLite functions between when sqlite3_prepare_v2 failed and where you log the error message.
The most common problem is that it reports that there is no such table. And if that's what you see, in this case that could be a result of failing to include the database in the app bundle (see the "Copy Bundle Resources" section of the "Build Phases" section of your target settings).
Alternatively, if it says something about the database is busy, that can happen if you have mismatched your database open calls and your database close calls (like you have in this code sample).
please make sure your sqlite db is not opened with any sqlite db browser when you are running app in simulator.
It happened with me, I had my sqlite db opened in sqlite browser to test my query and when I was running app from simulator it was not updating anything in db.
The problem was my file was of sqlite extension, but the code specified an extension of sqlite3. I thought the two were synonymous but they weren't

SQLite Persistence project : errorMsg

I use errorMsg in my NSAssert, but I only defined it as NULL and never used it to get the actual error message. So, it will always be NULL and there is no point to use it in NSAssert.
<...>
char *errorMsg = NULL;
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(database, update, -1, &stmt, nil)
== SQLITE_OK) {
sqlite3_bind_int(stmt, 1, i);
sqlite3_bind_text(stmt, 2, [field.text UTF8String], -1, NULL);
}
if (sqlite3_step(stmt) != SQLITE_DONE)
NSAssert(0, #"Error updating table: %s", errorMsg);
<...>
will anyone give a solution?
when I run the app, there is no harm. but then, when I press the home button, the process paused and shows me this:
2013-05-20 23:57:50.156 SQLite Persistence[5373:c07] * Assertion failure in -[LPEViewController applicationWillResignActive:], /Users/Me/Developer/SQLite Persistence/SQLite Persistence/LPEViewController.m:84 2013-05-20 23:57:50.158 SQLite Persistence[5373:c07] Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Error updating table: (null)' ** First throw call stack: (0x2094012 0x11a1e7e 0x2093e78 0xc37665 0x3c09 0xc624f9 0x20ee0c5 0x2048efa 0xb96bb2 0xe2bb1 0xe2c3d 0xece0c 0xf5e74 0xf6beb 0xe8698 0x1fefdf9 0x1fefad0 0x2009bf5 0x2009962 0x203abb6 0x2039f44 0x2039e1b 0x1fee7e3 0x1fee668 0xe5ffc 0x2b4d 0x2a75) libc++abi.dylib: terminate called throwing an exception (lldb)
A couple of issues:
You never set the errorMsg. Make sure to set it to sqlite3_errmsg (or just use that function directly).
Your custom error message ("Error updating table") is a little misleading, too, as it would imply that you're reporting the name of a table, whereas your choice of variable name suggested you really wanted to report the SQLite error message.
If sqlite3_prepare_v2 fails, you don't report any error message. Furthermore, rather than stopping and reporting an error if sqlite3_prepare_v2 failed, you proceed to try to call sqlite3_step, even though there's no valid statement to perform. The problem with that is that it would undoubtedly replace the meaningful error message you would have received after sqlite3_prepare_v2 failed with some useless message about executing statements in the wrong order.
You don't check the success or failure of your sqlite3_bind statements. It would be prudent to do so (though I suspect you're more likely to fail at the sqlite3_prepare_v2 statement).
Anyway, maybe you want something like:
sqlite3_stmt *stmt;
if (sqlite3_prepare_v2(database, update, -1, &stmt, nil) != SQLITE_OK)
NSAssert(0, #"prepare failure: %s", sqlite3_errmsg(database));
if (sqlite3_bind_int(stmt, 1, i) != SQLITE_OK) {
sqlite3_finalize(stmt);
NSAssert(0, #"bind 1 failure: %s", sqlite3_errmsg(database));
}
if (sqlite3_bind_text(stmt, 2, [field.text UTF8String], -1, NULL) != SQLITE_OK) {
sqlite3_finalize(stmt);
NSAssert(0, #"bind 2 failure: %s", sqlite3_errmsg(database));
if (sqlite3_step(stmt) != SQLITE_DONE) {
sqlite3_finalize(stmt);
NSAssert(#"step error: %s", sqlite3_errmsg(database));
}
sqlite3_finalize(stmt);
Whether you want to use NSAssert or just NSLog and immediately return, I'll defer to you, but this code sample will check more SQLite failure conditions and report meaningful errors.

Convert error codes to text in iOS

I have a wrapper for encrypting and decrypting using CommonCryptor. Occasionally the decryption process will fail, in which case I fill an error like so:
if (result == kCCSuccess) {
cipherData.length = outLength;
} else {
if (error) {
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:nil];
}
return nil;
}
And then I log the error like this:
if (error != nil) {
DDLogError(#"Decrypt fail %i, %#", [error code], [error localizedDescription]);
}
However, this ends up generating strings like:
2013-01-09 09:15:19.753 [BridgeEncrypter decryptDataFromData:] [Line 83] E: Decrypt fail -4304, The operation couldn’t be completed. (com.***.bridgecrypt error -4304.)
Where the -4304 could be any of the error codes in CommonCryptor.h (-4300 to -4305). Is there a good way to map the error codes to their string values, or do I need to have a switch statement that adjusts the string by hand? If I do have to depend on a switch, would best practice be to put it where the issue is logged or where the error is generated?
I'm not sure what you're looking for here. I'm not familiar with CommonCryptor or how error messages are handled in it.
I can recommend that you lean on NSError and it's userInfo and NSLocalized*Key feature.
For example, if you set a NSLocalizedDescriptionKey in the userInfo dictionary, error:
NSDictionary userInfo = #{
NSLocalizedDescriptionKey : #"This is the error message I want users to see"
};
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:userInfo];
Then This is the error message I want users to see is the string returned by -localizedDescription. Then the calling code can use the string to display a message to the user without needing to reinterpret it.
As to the question of how to link error codes to messages you want users to see, there could be a CommonCryptor function that converts error codes to human readable string. If not, then you could write your own. I would recommend using a switch.
NSString *MyCodeToLocalizedDescription(CCCryptorStatus cryptorStatus)
{
switch(cryptorStatus) {
case kCCDecodeError: return #"This is the error message I want users to see";
…
default: return #"Oh noes, unknown error";
}
}
At that point setting the error is:
NSDictionary userInfo = #{
NSLocalizedDescriptionKey : MyCodeToLocalizedDescription(result)
};
*error = [NSError errorWithDomain:kBridgeEncryptorErrorDomain
code:result
userInfo:userInfo];

HTTP request over CFStream

I am trying to get simple HTTP communications working using CFStream, however with the below code I still get a connection success even when I give an invalid URL (wwwww.yahoo.com).
Can someone point to me what is wrong with this code? I am expecting the call to CFReadStreamOpen() to fail but it is succeeding even though the URL is bad.
I haven't been able to find a simple CFNetwork example which does HTTP (without use of NSURL) that works on ARC. If anyone knows of such sample code please let me know.
- (void) test
{
CFStringRef m_host = CFStringCreateWithCString(NULL, "wwwww.yahoo.com", kCFStringEncodingASCII);
int m_port = 80;
CFHostRef host;
NSLog(#"Attempting to (re)connect to %#:%d", m_host, m_port);
{
CFReadStreamRef m_in = NULL;
CFWriteStreamRef m_out = NULL;
host = CFHostCreateWithName(kCFAllocatorDefault, (CFStringRef)m_host);
if (!host)
{
NSLog(#"Error resolving host %#", m_host);
}
CFStreamCreatePairWithSocketToCFHost(kCFAllocatorDefault, host , m_port, &m_in, &m_out);
CFRelease(host);
CFStreamClientContext context = {0, nil,nil,nil,nil};
if (CFReadStreamSetClient(m_in, kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkReadEvent, &context))
{
CFReadStreamScheduleWithRunLoop(m_in, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
}
if (CFWriteStreamSetClient(m_out, kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered, networkWriteEvent, &context))
{
CFWriteStreamScheduleWithRunLoop(m_out, CFRunLoopGe tCurrent(),kCFRunLoopCommonModes);
}
BOOL success = CFReadStreamOpen(m_in);
CFErrorRef error = CFReadStreamCopyError(m_in);
if (!success || (error && CFErrorGetCode(error) != 0))
{
NSLog(#"Connect error %s : %ld", CFErrorGetDomain(error), CFErrorGetCode(error));
[NSThread sleepForTimeInterval:5.0];
}
success = CFWriteStreamOpen(m_out);
error = CFReadStreamCopyError(m_in);
if (!success || (error && CFErrorGetCode(error) != 0))
{
NSLog(#"Connect error %s : %d", CFErrorGetDomain(error), CFErrorGetCode(error));
[NSThread sleepForTimeInterval:5.0];
}
else
{
NSLog(#"Connected");
}
}
}
For asynchronous code such as yours, you need to set up the delegate and catch the error there. Check out http://iphonedevsdk.com/forum/iphone-sdk-development/17542-cfstream-catch-error-in-connection.html
According the the Apple Developer site, "If the stream can open in the background without blocking, this function always returns true.". Meaning the request to open the stream is sent out on a different thread and hence the function returns true when you call it and starts the connection process on the background thread. All read/write calls on the respective streams then become blocking until the background thread finishes opening up the stream. You will be able to see this if you set up a break point on "CFReadStreamOpen(m_in);" and see what happens after that single line executes. Hope this answers your question.

Resources