Hi Guys,

I am trying to fix an crash issue. On loading an tableview everything works fine but if the user is trying to scroll up and down faster the fields displayed gets removed.

Each fields are taken from the dB and displayed. As a result of fast action the values from DB returns Nil thus app crashes.. if Handling crash then it show empty fields.

Error on console:

[Main thread]Error while executing sql query:

(Too many open cursors)

SQLCODE: -1230

NSLocalizedFailureReason: Too many open cursors

NSURL: http://dcx.sybase.com/ulerr?id=-1230&version=1201⟨=en

NSLocalizedDescription: Error while executing sql query:

I can see that each statement is closed at some part in applicaiton.

I knew this looks wierd . Please put up your suggestion here.

asked 03 Oct '18, 04:58

Dinesh2516's gravatar image

Dinesh2516
26114
accept rate: 0%

This is guesswork... It is most likely a program design error, where the code to close a cursor is not actually being executed at runtime, perhaps because an interruption or exception of some kind occurs and is not explicitly handled before another copy of the cursor is opened.

(03 Oct '18, 10:15) Breck Carter

Hi Breck Carter thanks for your quick response. I am completely new to this SQL. I can see that each statement is closed when new statement is created.

Do we have any method to close the cursor or Closing statement will do that ?

Sorry if i am not making any sense.

(03 Oct '18, 10:19) Dinesh2516
Replies hidden

Please post your code.

(03 Oct '18, 10:47) Breck Carter
func prepareStatement(_ sql:String) -> Bool{
        queryString = sql
        if sql.isEmpty {return false}
        if statement != nil{

            statement?.close()
            statement = nil
        }
        //Logger.debug("Preparing statement \(sql)", className: #file)
        statement = DataAccess.sharedInstance().prepareStatement(sql)
        return statement != nil

    }
(03 Oct '18, 10:49) Dinesh2516

UltraLite imposes a limit on the number of open cursors (result-sets). Applications don't typically require a large number of active cursors, so this acts as an indication that cursors are not being closed properly. (The limit is around 64.)

You have wrapped the UltraLite C++ API with Swift, which is good. I will talk about the underlying C++ API.

ULResultSet and ULPreparedStatement objects must both be closed when you're done using them. Use the Close() method on each to do this. (When you Close() a connection, that automatically closes all attached objects, but this isn't something you should rely on.)

As a debugging aid, you can call the ULConnection::GetChildObjectCount() method to determine how many objects are currently allocated for that connection. This will count both prepared statement and result set objects, as well as some schema objects if you are using those. If you have closed everything, the count will be zero. As your application runs, the count should remain roughly constant. To start, you could try logging this count every time you open a new result set, and add further check points if required to narrow down the leak.

When servicing requests for data from the tableview, you have two main options I think: either keep a cursor open and do relative or absolute fetches on it as required, or, pre-fetch all of the data into memory and close the cursor. The latter is simpler and works well as long as the list isn't too large, though you may need to perform the bulk fetch on a separate thread/task.

permanent link

answered 03 Oct '18, 14:24

Tim%20McClements's gravatar image

Tim McClements
2.0k1830
accept rate: 35%

Thank you so much Tim. I am happy that you have got my issue. The problem is i am new to this SQL DB and this current setup. With your help i have found the that there is almost 115 count from the ULConnection::GetChildObjectCount(). So there is some issue with allocation of the object. Below is the code did you find anything weird on this ? The same code base for Statement as well.

+(instancetype)setWithULResultSet: (void*)set{
    if (set == nil) return nil;
    ResultSet *object = [[super alloc] init];
    if (object){
        object->pSet = set;
    }
    return object;
}

-(instancetype)init {
    if (self = [super init]) {
        pSet = NULL;
    }
    return self;
}
(04 Oct '18, 08:02) Dinesh2516
Replies hidden
1

There's more code than that :-) That is just initializing the Objective C wrapper object, right?

The 'set' parameter (which should be type ULResultSet , rather than void , yes?) is created by a call to ExecuteQuery() on a ULPreparedStatement object. You must call Close() on both the result set and prepared statement when done with them. Where that Close call happens depends on how your code is architected. If ownership of the ULResultSet is effectively passed to this wrapper object, maybe the Close should happen when the wrapper is deallocated?

Please have a look at ulcpp.h and the documentation to see how these classes work and match that up with your existing code. A basic usage example can be found in samples/ultralite/starter/ulsample.cpp.

(04 Oct '18, 11:31) Tim McClements
Your answer
toggle preview

Follow this question

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or _italic_
  • **bold** or __bold__
  • link:[text](http://url.com/ "title")
  • image?![alt text](/path/img.jpg "title")
  • numbered list: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Question tags:

×161
×24

question asked: 03 Oct '18, 04:58

question was seen: 1,242 times

last updated: 04 Oct '18, 11:31