Possibly bad memory access? - objective-c

I am currently developing on Objective-C using sqlite3. The following code seems like a bad memory access.
-(sqlite3_stmt *)PrepareStmt:(NSString *)query
{
//...
const char *query_stmt = [query UTF8String];
sqlite3_stmt *stmt = nil;
int retval = 0;
if ((retval = sqlite3_prepare_v2(db, query_stmt, -1, &stmt, nil)) == SQLITE_OK)
{
return stmt;
}
else
{
//Error handling...
}
}
- (void)SomeFunc
{
NSString *query = #""; //Assume valid SQL statement
sqlite3_stmt *stmt = [self PrepareStmt:query];
//Use stmt, like step, etc.
sqlite3_finalize(stmt);
}
The sqlite3_stmt in PrepareStmt is set to nil and it will be an out parameter from sqlite3_prepare_v2(). The memory should be allocated in that function. Therefore, it should be released by calling sqlite3_finalize().
My question here is that if we return sqlite3_stmt from PrepareStmt(), it should be still valid right? The local pointer in PrepareStmt() is already popped off the stack, but the memory allocated by sqlite3_prepare_v2() should still be valid.
Is this thinking valid? Or do I need to pass in an address of an pointer to PrepareStmt()?
Thank you!

Yes it's valid in this case. But note that sqlite3_finalize() isn't just about releasing memory (i.e. dealloc). It also sends a message to the DB to tell it to drop it's precompiled SQL statement, etc...

Related

How to set sslmode as allow in postgresql in Objective-C

I used the following code to connect to the postgresql database. It works good. But now I want to connect it with sslmode enabled. Can anyone help me to acheive this.
NSString* portS = [NSNumber numberWithInteger:port].stringValue;
headerPG = PQsetdbLogin(serverName.UTF8String,portS.UTF8String,NULL,NULL,databaseName.UTF8String,
userName.UTF8String, password.UTF8String);
BOOL result = [self connected];
NSString *resultString;
if(!result){
//Error connection
[self errorPG];
resultString = #"Connection Failed";
}
else{
resultString = #"Connected Successfully";
}
return resultString;
I dont know how to use the following function.
PGconn *PQconnectdbParams(const char **keywords, const char **values, int expand_dbname);
How to feed data in keywords, values, etc.
Thanks in advance.
I got the answer myself.
const char *const keywords[] = {[#"sslmode" UTF8String], [#"hostaddr" UTF8String], [#"port" UTF8String], [#"user" UTF8String], [#"password" UTF8String], [#"dbname" UTF8String]};
const char *const values[] = {[#"allow" UTF8String], [serverName UTF8String], [portS UTF8String],[userName UTF8String],[password UTF8String],[databaseName UTF8String]};
headerPG = PQconnectdbParams(keywords, values, 1);
Here the keyword array has the keywords of postgresql and value array has the values of particular key in keyword array.

Objective C: SQLite where-statement wont work when running another method first

So basically I have an app that will provide tasks based on selected project. Both projects and tasks are stored in a SQLite database.
To get the current project id I compare the selected project (_selectedProject) to my database, to get the ID. This is done in my getSelectedProjectId method. However, when running this method in the getTasks method, the Where-statement wont work at all. If I don't run the getSelectedProjectId method first, it works just fine. Am I forgetting to release something? Or is it something else? Any ideas?
I'm pretty new to both SQLite and Objective C, so this may not be a complex issue. I have made sure the getSelectedProjectId method returns the correct project ID. I have also made sure the query that is run in the getTasks method is correct, and when running it through my terminal it returns a number of rows. In the app it returns nothing, provided I'm running the getSelectedProjectId somewhere in that method first.
This is the method that fetches the tasks:
- (void)getTasks
{
[self openDB];
sqlite3_stmt *statement;
int projectId = [self getSelectedProjectId];
NSString *query = [NSString stringWithFormat:#"SELECT * FROM tasks WHERE project_id=%i", projectId];
const char *query_statement = [query UTF8String];
sqlite3_prepare_v2(_contactDB, query_statement, -1, &statement, NULL);
while (sqlite3_step(statement) == SQLITE_ROW)
{
// I add the task title to my array of tasks here.
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
}
And this is the method that gets the correct project id from the database:
- (int)getSelectedProjectId
{
sqlite3_stmt *statement;
NSString *query = [[NSString alloc]
initWithFormat:#"SELECT id FROM projects WHERE title=\"%#\" LIMIT 0,1",
_selectedProject];
int rowId = 0;
const char *query_statement = [query UTF8String];
[self openDB];
sqlite3_prepare_v2(_contactDB, query_statement, -1, &statement, NULL);
if (sqlite3_step(statement) == SQLITE_ROW)
{
rowId = sqlite3_column_int(statement, 0);
}
sqlite3_finalize(statement);
sqlite3_close(_contactDB);
return rowId;
}
The problem occured because I closed the DB connection in my getSelectedProjectId-method. I'm now leaving my DB open instead, works like a charm.

Return strings in sequence from NSMutableArray [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 9 years ago.
I have a NSMutableArray with comma separated strings for an objective-c iphone application (iOS SDK 6.0). I need a simple function that, when triggered, returns a string, one at a time, from string 0 onwards. To give you some context, a user would click a button, and for every click a new string is returned, in order, from the Array. It's a list of previously saved "favourite quotes". The string is displayed in a UITextView.
Ideally, I would also have a function for reversing, i.e. going backwards in the array from the current position.
This might be pretty basic, but I seem to only be able to find more advanced implementations that I'm unable to translate into this looping backwards and forwards in an Array of strings.
EDIT: Current code for this function below. I need to add the part where one string at a time is returned from the array (allRows) and displayed in a textview
- (IBAction)nextQoute:(id)sender {
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_qoutesDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:
#"SELECT qoutesSaved FROM qoutes"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_qoutesDB,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableArray *allRows = [[[NSMutableArray alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *qouteField = [[NSString alloc]
initWithUTF8String:
(const char *) sqlite3_column_text(
statement, 0)];
NSString *str = [NSString stringWithFormat:#"%#", qouteField];
[allRows addObject:str];
[qouteField release];
}
Very thankful for help!
You mention that you are new to Objective C, and based on how I read what you're describing, I wonder if you are making this a lot more complicated than it needs to be. Items in an array (that is, NSArray, or NSMutableArray) aren't "seperated" by anything - different items in an array are accessed by their order in the array, called an index. So in your code, when you build allRows, each str that you put into it gets put into its own index, and to get it back out of the array, you just use that index.
For example, let's pretend your quotes you are pulling from your database are:
"Here's looking at you kid"
"I'll be back"
"It's a trap"
If they are put into the array in that order, and you want to put "It's a trap" into a textfield (called myTextField), you just write
myTextField.text = [allRows objectAtIndex:2];
In the end, that means what you probably want to do for your app is keep a counter you pass to objectAtIndex. When the user clicks the forward button, increase the count. When they click the back button, decrease the count. Then, call the code I put above, except instead of sending the value 2, send your counter variable. As mentioned in the comments to H2CO3s answer, make sure you put some validation in there to prevent your count from going beyond the limits of your array, or you'll get a nasty crash. If this is indeed what you are trying to do and you are still confused, I can add some more code.
I'm not too familiar with accessing a sqlite database the way you do here (I use CoreData, so the calls are very different), so perhaps I am completely mistaken about what you are trying to do here - but this seems like a very simple task that is being very overcomplicated.
You can just keep track of the string index in an instance variable (or if you don't have an object to work with because you write a class method or a function and not an instance method, then you can use a static local variable too).
#interface Foo: NSObject {
NSInteger index;
NSArray *strings;
}
// ...
- (NSString *)nextString
{
return index < strings.count ? strings[index++] : nil;
}
- (NSString *)previousString
{
return index > 0 ? strings[--index] : nil;
}
You can fetch the whole data in database.And store it one array
declare these two objects.
#interface YourClassName: NSObject {
NSInteger stringIndex;
NSArray *quoteFieldDataArr;
}
NSMutableArr *quoteFieldDataArr=[self fetchDataFromDataBase];
-(NSMutableDictionary *)fetchDataFromDataBase
{
const char *dbpath = [_databasePath UTF8String];
sqlite3_stmt *statement;
if (sqlite3_open(dbpath, &_qoutesDB) == SQLITE_OK)
{
NSString *querySQL = [NSString stringWithFormat:
#"SELECT qoutesSaved FROM qoutes"];
const char *query_stmt = [querySQL UTF8String];
if (sqlite3_prepare_v2(_qoutesDB,
query_stmt, -1, &statement, NULL) == SQLITE_OK)
{
NSMutableDictionary *allRows = [[[NSMutableDictionary alloc] init] autorelease];
while (sqlite3_step(statement) == SQLITE_ROW)
{
NSString *qouteField = [[NSString alloc]
initWithUTF8String:
(const char *) sqlite3_column_text(
statement, 0)];
NSString *str = [NSString stringWithFormat:#"%#", qouteField];
[allRows addObject:str];
[qouteField release];
return nil;
}
// Load Next String
- (NSString *)loadNextString
{
return stringIndex < quoteFieldDataArr.count ? quoteFieldDataArr[stringIndex++] : nil;
}
- (NSString *)loadpreviousString
{
return stringIndex > 0 ? quoteFieldDataArr[--stringIndex] : nil;
}

What is the right way to know if an object was initialized in a database?

I have a trouble in my database - somehow at some point it appears that a database is being closed even before it was opened.
If a database was not opened I am using the following statement: if (!database) then break;
when *database is being set to nil (database = nil) when it was not opened.
Am I doing it in a right way? Or there is some other error in my code?
Here is my code:
-(BOOL) loadDB: (NSString*) dbPath {
//Database was opened before
if (database) {
sqlite3_close(database);
database = nil;
}
//Opening database
if (sqlite3_open([dbPath UTF8String], &database) != SQLITE_OK)
{
database = nil;
return FALSE;
}
return TRUE;
}
The code is being called for multiple times and at some time it throws an exception. Why may this happen?
When I am using debugger to see where a problem occured, it shows me: sqlite3_close(database);
Thank you in advance.
Try setting the database pointer to NULL instead of nil.
-(BOOL) loadDB: (NSString*) dbPath {
BOOL retVal = TRUE
//Database was opened before
if (database) {
sqlite3_close(database);
database = NULL; // <-- NULL not nil
}
//Opening database
if (sqlite3_open([dbPath UTF8String], &database) != SQLITE_OK) {
database = NULL; // <-- NULL not nil
retVal = FALSE;
}
return retVal;
}
In Objective C nil is a nil pointer on an object. But database is a pointer to a struct, so use NULL instead.
Your close brace is too early (but I don't think that's the problem because it wouldn't compile.
As a style note, please only return ONE time from a function (and make that at the bottom). Create a BOOL, initialize it to TRUE and change it's value to FALSE when necessary.

Using pointers in Objective C for NSMutableArray objects

When retrieving objects from an NSMutableArray in cocoa-touch is the below code ok? Should I be allocating([alloc]) new Page objects each time or is just pointing to it alright? Do I need to do anything to the Page *pageObj after, such as set it to nil?
const char *sql = "insert into Page(Book_ID, Page_Num, Page_Text) Values(?, ?, ?)";
for (i = 0; i < ([[self pagesArray] count] - 1); i++) {
if(addStmt == nil) {
if(sqlite3_prepare_v2(database, sql, -1, &addStmt, NULL) != SQLITE_OK) {
NSAssert1(0, #"Error while creating add statement. '%s'", sqlite3_errmsg(database));
}
}
Page *pageObj = [[self pagesArray] objectAtIndex:i];
if(pageObj.isNew) {
sqlite3_bind_int(addStmt, 1, self.book_ID);
sqlite3_bind_int(addStmt, 2, pageObj.page_Number);
sqlite3_bind_text(addStmt, 3, [[pageObj page_Text] UTF8String], -1, SQLITE_TRANSIENT);
if(SQLITE_DONE != sqlite3_step(addStmt)) {
NSAssert1(0, #"Error while inserting data. '%s'", sqlite3_errmsg(database));
}
NSLog(#"Inserted Page: %i into DB. Page text: %#", pageObj.page_Number, pageObj.page_Text);
}
//Reset the add statement.
sqlite3_reset(addStmt);
}
Thanks. I also understand this should probably be in a transaction but I didn't quite get that working just yet.
The way you're declaring a pointer is correct. You don't need alloc, since that creates a new object, when you want to refer to an existing object in the array. You would want to retain it if you were going to keep the reference outside of that method, but since you're only using it temporarily it's fine not to.
The actual pointer variable will be destroyed and recreated every trip to the loop, so there's no need to set it to nil. Even if you declared the variable outside the loop, simply assigning it to a new object is fine. The only time you'd set it to nil is when you're releasing the object stored in the pointer (or the object may be released elsewhere). If you didn't set it to nil in that case, the pointer would refer to an invalid memory location after the object is dealloced, usually causing a crash.
One bug I can see though, you're skipping the last element in your array in your for loop by subtracting 1 from the count.
Aside from the previously mentioned count error, it looks good.
As far as transactions go, I highly recommend wrapping this write loop in one. It will greatly increase your write performance and I found that it helps with memory usage as well. I use the following class method to begin a transaction:
+ (BOOL)beginTransactionWithDatabase:(sqlite3 *)database;
{
const char *sql1 = "BEGIN EXCLUSIVE TRANSACTION";
sqlite3_stmt *begin_statement;
if (sqlite3_prepare_v2(database, sql1, -1, &begin_statement, NULL) != SQLITE_OK)
{
return NO;
}
if (sqlite3_step(begin_statement) != SQLITE_DONE)
{
return NO;
}
sqlite3_finalize(begin_statement);
return YES;
}
and this one to end a transaction:
+ (BOOL)endTransactionWithDatabase:(sqlite3 *)database;
{
const char *sql2 = "COMMIT TRANSACTION";
sqlite3_stmt *commit_statement;
if (sqlite3_prepare_v2(database, sql2, -1, &commit_statement, NULL) != SQLITE_OK)
{
return NO;
}
if (sqlite3_step(commit_statement) != SQLITE_DONE)
{
return NO;
}
sqlite3_finalize(commit_statement);
return YES;
}
I should probably store the SQL statements for later reuse, but these transaction statements are called much less frequently than my other queries.
Of course not. You have allocated it before and are just referencing the same object. No need to reallocate. Also you don't need to set it to nil.