Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updates to DBWrap #3

Open
peteshew opened this issue Dec 30, 2018 · 8 comments
Open

Updates to DBWrap #3

peteshew opened this issue Dec 30, 2018 · 8 comments

Comments

@peteshew
Copy link

Robert, I am planning to replace SQLite for a multiple computer environment and Firebird has what I need. My project is good old fashioned C++ in MS Visual Studio (no .net or MFC) so DBWrap++ is pretty nearly perfect.
However, I prefer to be able to access result variables by field/column name and so I have added that feature. Performance would suffer a bit, but my transaction rates are very low, so no issue.
I like the event feature of Firebird so that notifications of changes can be used to update the presentation very quickly, so I have added support for that too.
Attached are the files with commented changes that I have made. I have tested on W10 64 bit with both 32 and 64 bit builds with and received alerts from changes made on another computer. The tests were run against Firebird 3.0 running as a Windows service.
DBWrapUpdates_PeteShew.zip
Feel free to ignore me, regards, Pete Shew.

@rtravis
Copy link
Owner

rtravis commented Dec 30, 2018

Thank you for your contribution. I will review and integrate your work into DbWrap-FB in the first two weeks of January 2019. The notifications feature looks useful. I'll probably change the named query parameter access to be optional based on a setting.

@peteshew
Copy link
Author

peteshew commented Jan 5, 2019

For my purposes, I have also added a default constructor to DbConnection and made the "connection" method public. This is so that the DBConnection declaration can have function scope while I try a possible remote server and then the localhost server with nested try blocks. (I could have used a pointer for subsequent activity, but I like this better).
Pete

@rtravis
Copy link
Owner

rtravis commented Jan 6, 2019

I was integrating the changes related to the database events and came across this note in the documentation:

"Note isc_que_events() cannot be called from within event_function."

The interdiction might be due to some thread safety issues in the Firebird library.

I think that I will remove the call to "isc_que_events" from the event callback function, rename "enableEvents" to something like "enableEventsOnce" and let the user reset the events if she needs subsequent events.

I also noticed that there are some fake events generated by Firebird the first time when "isc_que_events" is called. I will suppress those events as I don't see any utility in them.

Let me know your opinion about the changes.

@rtravis
Copy link
Owner

rtravis commented Jan 16, 2019

I integrated the event callback changes to a development branch (see commit d298db8). I had to use a mutex to prevent a crash that occurred when an event callback was called after the DbConnection object was destroyed. I will look over your other changes later this month. Thanks.

@peteshew
Copy link
Author

I sent you a couple of messages using 'reply', but I don't think you have received them. I responded to your message about re-enabling events in the callback with an alternative approach. Did you get it?

@rtravis
Copy link
Owner

rtravis commented Jan 19, 2019

Unfortunately I did not receive your reply.

@peteshew
Copy link
Author

Sorry about the mis-communication. I thought about the potential thread issue of re-enabling the events in the callback and came to the conclusion that the safest way to handle it would be to have a single call back to the application callback with the details of the alerts, which also has the effect of, potentially, reducing the number of calls to the application callback routine.

The application callback would then set notification statuses in a way most appropriate to the application, including one for the application to make a call to DbConnection to re-enable the events before promptly returning.

The approach I have been testing uses individual addNotification method calls for each trigger name, passing the name and a void* with user data. Theses are saved in a vector in the DbConnection class. There is also a removeNotification method.

The method enableNotifications passes the application callback (may be omitted for re-enable calls) and a void* for userdata. It uses the vector to build the parameters for the isc_event_block call. There is also a disableNotifications which also optionally clears the vector.

The callback iterates the vector adding any new event counts and building a temporary vector of entries with a non-zero count and clearing the counts in the vector. The temporary vector is passed to the application's callback together with the enable events userdata.

In the test program, the callback increments a counter, which is decremented in the main thread from time to time whilst re-enabling the events. I used a counter to avoid thread complications.

In my Windows program, the application callback posts Windows messages for each event to each interested party as well as a post to let the main thread know that events need to be re-enabled. (PostMessage is asynchronous and handled by the main application thread, whereas SendMessage is effectively a call so is in the same thread as the callback.)

I am including my current copy of DbConnection.h, DbConnection.cpp and FbDbUnitTest.cpp

I am also including a header only file for accessing Firebird date type fields as Unix epoch time_t data. This may be of use, maybe not. Once I had worked out that dates, but not times, were in 'modified Julian date' form, converting to time_t was straightforward. Going the other way, the only way to get the information into a date or timestamp format in SQL was to insert a DATEADD function. Messy but it works.

DbConnection.zip

@peteshew
Copy link
Author

peteshew commented Feb 1, 2019

Robert, can I suggest adding DbRowProxy::getTimestamp and a DbStatement::setTimestamp methods. I propose using a double as an opaque container for the Firebird date and time values; this would clearly distinguish it from int64_t values and reduce confusion. ("getInt64" reverses the order of the words so using setInt has no easy way to distinguish timestamps and get the correct result)
Conversion routines to and from time_t and struct tm (with loss of the milliseconds) could also be provided.
I am searching for updates since the last time I looked, so getting and using millisecond timestamps in select statements without needing to decode would fit nicely with this approach.
Pete

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants