How do I set an attribute on an ODBC connection via DBExpress? - delphi

Justification that you might as well skip reading but is included to filter out people telling me not to do something that I'm not sure of in the first place.
I'm trying to debug some multithreaded database hoopla, it's mostly experimental although if I get it working I'd be a very happy guy. I'm very new to DBExpress (only have been using it for 4-5 hours). I'm not using TSQLConnection or any designtime components because I'm trying to rewrite an existing ODBC32.dll interface in a painless an unnoticed way and once I'm done, I'll expose the rest of the awesomeness. The reason I mention this is because it's very apparent that I'm not using dbexpress in the normal way shown in many of the tutorials.
Here's the question
I'm using the TDBXConnection and connecting to an ODBC datasource, I want to try setting the SQL_ATTR_ASYNC_DBC_FUNCTIONS_ENABLE parameter on my connection, but I don't have a clue where to go about setting that particular parameter.

You've got FDBConnection : TDBXConnection; defined somehwere else so now you've got to:
....
begin
if FDBConnection is TDBXOdbcConnection then
with FDBConnection as TDBXOdbcConnection do
begin
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_ENABLE, Pointer(SQL_ASYNC_ENABLE_ON), 0);
MethodTable.SQLSetEnvAttr(EnvironmentHandle, SQL_ASYNC_DBC_FUNCTIONS, Pointer(SQL_ASYNC_DBC_CAPABLE), 0);
end;
end;
That's pretty painless.
Include Data.DBXODBC and System.ODBC in the uses and you're golden.

Related

How to treat non design component initialization errors?

For start, lets take an exemplification:
You create a new VCL application project in Delphi and put a TIBDataBase and type in the path and name of the database file with the extension .IB ok?
Now, If you you just put example.ib and leave the path behind, when you execute your application without Delphi, it will open the database normally if the .EXE is in the same path as the .IB but if you run your application from Delphi, it will raise an error because it can't find the database file, because Delphi changes the working directory.
Sometimes you want to leave the Active property of that component set to True while you are developing, and them set to False and change it during the start of the application, when you deliver to your client. All that because he/she may want to install in a different path and your application has to find the proper place of the database before open it.
The problem comes when you already delivered to your client and still make some changes everyday on the code. You then have to deploy at least once a day, and sometime you just forget to set that property back to False and when the client receives the update and tries to run it, he/she gets a not found database error.
The question is, how can I handle that error if this opening happens automatically when the component is loaded in memory and the activation of the database does not happens in my own code?
I do not think you are going to find a general solution to preventing run time exceptions from design time property settings without modifying the component or deriving a descendent.
For TIBDatabase, set the property AllowStreamedConnected to False. This stops TIBDataBase from automatically connecting to the database at run time when Connected is True at design time. TIBQuery using this TIBDatabase will not open even it is set Active at design time.
Some other database connection components have similar properties.
Regarding the database issue only: if I understand you correctly, my solution requires you to write an event handler for the 'BeforeConnect' event as shown below:
procedure TDM.SQLConnection1BeforeConnect(Sender: TObject);
var
dir: string;
begin
with TRegIniFile.create (regpath) do // I keep my database locations in the registry
begin // but you can use any method of getting the location
dir:= ReadString ('firebird', progname, '');
free
end;
with sqlconnection1 do
begin
close;
params.values['database']:= dir;
loginprompt:= false;
end;
end;
This way, you can have one location stored in your database for local use, but have different locations for different users.

Lazarus Free Pascal / Delphi - RunError 211

I'm trying to connect my Windows XP program (Lazarus) to my Ubuntu postgres server.
When the Lazarus program runs, it seems to compile fine but I get this error:
Project ... raised exception class 'RunError(211)'.
Then it terminates execution (and I don't see any output), and opens up a file customform.inc. In that file, it shows a procedure procedure TCustomForm.DoCreate; where it highlights a line: if Assigned(FOnCreate) then FOnCreate(Self);
I believe this is one of the system's files.
I never get to see any output.
What could this be? Thanks!
MORE INFO:
I've narrowed down the error to this line:
dbQuery_Menu.SQL.Text:='Select * From "tblMenus"';
dbQuery_Menu.Open;
the exception is triggered when the OPEN statement gets executed.
BTW, dbQuery_Menu is defined as a TSQLQuery component.
Clueless! :(
Run error 211 appears when you try to call an abstract method. Check this link from more information on FreePascal/Lazarus runtime errors.
Since you say all is done by code and you have no visual components, the problem probably lies in your code trying to use an ancestor component which has not overriden the Open method. You should be able to solve this by using the correct descendant component.
Another possibility, although I would strongly recommend to avoid this one, is to override the Open method yourself. It should be avoided because if you are using an ancestor component then you probably would have to override more abstract methods.
HTH
After nearly 5 days I found the answer. Many thanks to all thos e ho have contributed with their ideas ESPECIALLY RRUZ, RBA and Guillem Vicens. there are other related posts all connected to getting the FIRST Lazarus program working with PostgreSQL.
Summary.
The biggest mistake I made here was that I used the TSQLConnection component. Don't do this. Instead use the TPQConnection.
Everything is done through code. We're not using any draggable components from the top tab.
Don't rely on the Lazarus docs (wiki) at least for working with PG DBs.. It is outdated. Some of the examples can be pretty misleading.
Make sure that fields have some default values. For example, if a Boolean field has no true or false (t/f) set, this may lead to errors.
And that's it! I hope many postgres+Lazarus newbies will find this useful.
From here - http://www.network-theory.co.uk/docs/postgresql9/vol2/SQLSTATEvsSQLCODE.html - -211 (ECPG_CONVERT_BOOL) This means the host variable is of type bool and the datum in the database is neither 't' nor 'f'. (SQLSTATE 42804)

How to read and write dbf in a native way?

In Delphi for Win32, how to read and write a dbf file in a native way, without the BDE? I know there are some components available in the web, but I have never used any of them, so I don't know which to choose (if any).
You can use ADO to access a DBF File
See ths sample code (using an TAdoConnection and TAdoDataSet components).
var
dbf_folder : string;
begin
dbf_folder:='c:\bdd';//set your dbf folder location here
ADOConnection1.LoginPrompt:=false;
ADOConnection1.ConnectionString:=Format('Provider=Microsoft.JET.OLEDB.4.0;Data Source=%s;Extended Properties=dBase IV;',[dbf_folder]);
try
ADOConnection1.Connected:=True;
ADODataSet1.CommandText:='Select * from file.dbf'; //make your SQL query using the name of the dbf file
ADODataSet1.Open;
while not ADODataSet1.eof do
begin
//do your stuff here
//ADODataSet1.FieldByName('').AsString
ADODataSet1.Next;
end;
except
on E : Exception do
ShowMessage(E.Message);
end;
end;
I used TDBF back when I was still working with DBF files (some legacy apps). I still use it for maintainance of those apps here and there. It is free, has a lot of features and works good.
I used Topaz from Software Science for many years before I got started with Firebird. It was always an excellent library, had a terrific manual and good technical support. It supports indexes and even has an in-memory option. I think it would be a good choice.
Apollo Database VCL.
ADO didn't work for me but I managed to open my dbf file using BDE:
From a Data Access (or BDE, depends on your version of Delphi) section I put a TDataBase and, TTable components (you can use TQuery if you want).
By doubleclick on TDataBase component I opened the setup dialog. Filled the Name field with 'db_name' (the name is arbitrary), driver name = 'STANDARD', Parameters field: 'PATH=C:\Path\To\DBF_FILES\'.
Then I set Connected=True.
Then in TTable component I set DatabaseName = 'db_name' - the one I set in TDataBase component. And TableName property set 'DB_FILE.dbf' which was located in the specified folder.
Active = True.
You know what to do next
It is not hard to read a DBF file if you don't need indexes. The format is pretty straightforward. A header followed for fixed sized registers. There is a flag in each register which indicates if it is deleted or not. I suggest looking for a component which does what you want. You can find some in Torry's Delphi pages.

How to filter Delphi 2010 compiler output (hints)?

I'm trying to get rid of some hints(*) the Delphi compiler emits. Browsing through the ToolsAPI I see a IOTAToolsFilter that looks like it might help me accomplish this through it's Notifier, but I'm not sure how to invoke this (through what xxxServices I can access the filter).
Can anyone tell me if I´m on the right track here? Thanks!
(*) In particular, H2365 about overridden methods not matching the case of the parent. Not so nice when you have about 5 million lines of active code with a slightly different code convention than Embarcadero's. We've been working without hints for months now, and we kinda miss 'm. :-)
Even if you could query BorlandIDEServices for IOTAToolsFilter, that interface isn't going to help you do what you're asking. That interface was introduced as part of a mechanism for adding additional build tools (compilers, etc.) to the IDE (before the IDE used MSBuild). It allowed you to write a custom "filter" to handle output from a particular build tool, but it would not let you apply a filter to one of the built-in tools (like the delphi compiler).
The reason the Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) call fails in Delphi2010 is that once MSBuild support was added to the IDE, the old way of adding build tools to the IDE was disabled, and the BorlandIDEServices interface no longer supported IOTAToolsFilter.
The declaration of IOTAToolsFilter should probably have been marked deprecated in ToolsAPI.pas (or least it should have been mentioned in the source code comment that it is no longer supported).
As far as your desire to filter a particular hint, I'm not aware of a way to do that via the ToolsAPI. It seems like a reasonable thing that can be added to IOTAMessageServices (the ability to enumerate, filter, and possibly change the messages in the IDE's Message View). I would enter a request in QualityCentral for that.
Also, please vote for QC #35774 (http://qc.embarcadero.com/wc/qcmain.aspx?d=35774), as if that were implemented, you would not need to use the ToolsAPI for this sort of thing.
According to http://docwiki.embarcadero.com/RADStudio/en/Obtaining_Tools_API_Services it should be possible to access it directly using BorlandIDEServices, eg:
var
OTAToolsFilter: IOTAToolsFilter;
begin
if Supports(BorlandIDEServices, IOTAToolsFilter, OTAToolsFilter) then
ShowMessage('supports IOTAToolsFilter')
else
ShowMessage('IOTAToolsFilter NOT supported');
end;
However this doesn't return the desired interface in Delphi 2010 (you'll get the not supported message), so there's either an error in the documentation, or an error in BorlandIDEServices not returning the correct interface.

Delphi 5: Ideas for simulating "Obsolete" or "Deprecated" methods?

i want to mark a method as obsolete, but Delphi 5 doesn't have such a feature.
For the sake of an example, here is a made-up method with it's deprecated and new preferred form:
procedure TStormPeaksQuest.BlowHodirsHorn; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;
Note: For this hypothetical example, we assume that using the parameterless version is just plain bad. There are problems with not "using protection" - which have no good solution. Nobody likes having to use protection, but nobody wants to not use protection. So we make the caller decide if they want to use protection or not when blowing Hodir's horn. If we default the parameterless version to continue not using protection:
procedure TStormPeaksQuest.BlowHodirsHorn;
begin
BlowHodirsHorn(False); //No protection. Bad!
end;
then the developer is at risk of all kinds of nasty stuff. If we force the parameterless version to use protection:
procedure TStormPeaksQuest.BlowHodirsHorn;
begin
BlowHodirsHorn(True); //Use protection; crash if there isn't any
end;
then there's a potential for problems if the developer didn't get any protection, or doesn't own any.
Now i could rename the obsolete method:
procedure TStormPeaksQuest.BlowHodirsHorn_Deprecatedd; overload; //obsolete
procedure TStormPeaksQuest.BlowHodirsHorn(UseProtection: Boolean); overload;
But that will cause a compile error, and people will bitch at me (and i really don't want to hear their whining). i want them to get a nag, rather than an actual error.
i thought about adding an assertion:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');
...
end;
But i cannot guarantee that the developer won't ship a version without assertions, causing a nasty crash for the customer.
i thought about using only throwing an assertion if the developer is debugging:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
if DebugHook > 0 then
Assert(false, 'TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)');
...
end;
But i really don't want to be causing a crash at all.
i thought of showing a MessageDlg if they're in the debugger (which is a technique i've done in the past):
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
begin
if DebugHook > 0 then
MessageDlg('TStormPeaksQuest.BlowHodirsHorn is deprecated. Use BlowHodirsHorn(Boolean)', mtWarning, [mbOk], 0);
...
end;
but that is still too disruptive. And it has caused problems where the code is stuck at showing a modal dialog, but the dialog box wasn't obviously visible.
i was hoping for some sort of warning message that will sit there nagging them - until they gouge their eyes out and finally change their code.
i thought perhaps if i added an unused variable:
procedure TStormPeaksQuest.BlowHodirsHorn; //obsolete
var
ThisMethodIsObsolete: Boolean;
begin
...
end;
i was hoping this would cause a hint only if someone referenced the code. But Delphi shows a hint even if you don't call actually use the obsolete method.
Can anyone think of anything else?
How about something like
procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
if DebugHook > 0 then asm int 3 end;
// This method is Obsolete! Use XXXXX instead.
Abort; // Optional, makes method useless
// old code here . . .
end;
Kind of a compromise between an assertion and a showmessage. The developer just needs to hit F9 to continue. You could put in an Abort, and then the method would do nothing, and that would force them to switch methods and the break makes them aware of it.
Personally I would recommend upgrading to a newer version of Delphi. 2007 and 2009 are great releases and are really worth the upgrade.
What I've ended up using was a combination of opting into a system where you agree to not have any deprecated code, with output debug strings and breakpoints otherwise.
Like strict html, I've created a Strict define.
All the common units have the obsolete code defined out if Strict is defined. That way the developer has agreed that they will not have deprecated code in their project:
{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; overload; //obsolete
{$ENDIF}
procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean); {$IFNDEF Strict}overload;{$ENDIF}
{$IFNDEF Strict}
procedure TStormPeaksQuest.BlowHaldirsHorn; //obsolete
begin
OutputDebugString(PAnsiChar('TStormPeaksQuest.BlowHaldirsHorn is deprecated. Use BlowHaldirsHorn(Boolean)'));
//Don't debugbreak without a debugger attached!
if DebugHook > 0 then
Windows.DebugBreak;
...
end;
So if the developer wants to have proper code, suffering having to perform code-changes when new things are deprecated, they can:
{$DEFINE Strict}
If not, then there will always be an OutputDebugString, and anyone with Debug View can see (even customers). It's funny to see commercial software (even Microsoft's) with output debug strings left over.
And finally, if there's a debugger attached, then they'll get a debug breakpoint out of nowhere. If anyone asks about, i can take that opportunity to make fun of them.
This doesn't exactly answer your question but it might provide an alternative solution. Could you not update the original function with a default value...
procedure TStormPeaksQuest.BlowHaldirsHorn(UseProtection: Boolean = False);
...so that legacy code compiles and behaves the same but the new functionality is available to new developers.
Why do you want to do this and why don't you want to upgrade the Delphi version?
Without the deprecated tag you really have no clean option to filter the use of deprecated methods. So it depend on where you want to make the concession:
renaming catches the error at compiletime (unless there is another method/function with the same name within scope).
all other methods are only caught at runtime. And this has a risk of slipping into the production code.
What you can do, is create a deprecated log. This won't piss off anybody, and it is no complete disaster if it enters production code. But if your tests have full coverage, you will catch all the culprits. You only have to check the log file after a (test)run.
And of course the best way, is to use grep to find all the occurences of the code and change it.
I'd agree with an optional parameter if it'll do the job. But I can think of situations were optional params won't fit. For instance I have moved functions into new units but kept the olds ones and marked them as deprecated.
I guess whatever solution you go with will also depend on the discipline of your team. Do they actively take notice and work to correct all the hints and warnings for their apps? Hopefully they do but I am shamed to admit that the team I work with (including myself) do not stay on top of all the hints and warnings. Every now and then I fix as many hints & warnings as time permits and we absolutely should fix warnings but in reality we've got to get the job done and are more focused on new features and deadlines.
So my point is, even if you could mark them as deprecated or give a similar hint/warning, do you feel your team will take the time to change their code anyway?
It's not a total solution since you can't differentiate whether they've used the method or not but if it's available in Delphi 5 but you could use the $MESSAGE compiler directive to emit a warning at compile time.
Nothing says "Fix me!" like a compiler break.
That said, I have a colleague who regularly modifies the signatures of 'common code' routines... and yes it is annoying!
My preferred (i.e. our team isn't quite there yet :/) approach is as follows:
All developers must be able to easily perform a full build of all projects on their own machines.
Whoever decides to change common code should bear responsibility for the consequences. I.e. Fix all affected code.
Granted, sometimes said developer might not be ideally suited to properly implementing and verifying all fixes.
But, by the same token the developrs imposed upon to "adopt the new contract" in their own code might not be clear on the subtelties of the new contract. I.e.
Is there anything special that needs to be done in order to use protection?
How is the use of protection implemented?
What are the concerns as to how it could break existing code?
This is a major reason why a comprehensive set of test cases is important.
Generally you want the ripple effect of all the changes applied as soon as possible. I.e. While the finer details of the change are fresh in the originating developer's mind - before attention shifts to something else!
It should be a rare occurance that the ripple effect is so vast (thousands of lines) that you want to apply the change over an extended period of time.
If this is the case, then implement a simple code-metric gathering tool integrated into your build process to report the number of outstanding instances.
I consider point 2 to be of key importance, not least because it emphasises the need for cooperation and communication within the team.
Going back to my opening statement, the sooner you catch and fix an error, the better.
Let the compiler report a break! -- It's the "earliest opportunity" error reporting mechanism we have.
That's my 2 coppers! :D

Resources