Delphi: Text-blobs in ClientDataSet on Firebird 2.5 with ODBC - delphi

We have faced a very strange problem. We are running a firebird 2.5 database with the following table structure.
CREATE TABLE TEST (
ID INTEGER NOT NULL,
MEMO BLOB SUB_TYPE 1 SEGMENT SIZE 80,
DATO TIMESTAMP
);
ALTER TABLE TEST ADD CONSTRAINT PK_TEST PRIMARY KEY (ID);
We are using Firebird 2.5.1 + ODBC 2.0.0.151 on Windows 7.
We use Delphi XE, with TADOConnection + TADODataSet + TDataSetProvider + TClientDataSet to connect to the database.
The problem is when we insert (or update) a new record into the ClientDataSet and updating the field MEMO. (TMemoField) (This has been working perfekt in FB 1.5 and with all versions of MS SQL server).
Now with a firebird 2.5 database we get the error message "Arguments are of the wrong type, are out of acceptable range, or are in conflict with one another." when running from the Delphi IDE, but no error if we run outside.
The big problem is that the time part of the field DATO is gone when we update the field MEMO. If we don't include the MEMO field, everything is OK.
One other strange thing is that if we use the TADODataSet directly to update the fields, everything works fine. It's only when updated through the ClientDataSet it is a problem.
I have made a small demo project illustrating the problem.
Test.zip (1090 KB):
http://www.consultas.no/u/3037f738
All tips and hints will be highly appreciated!
Best regards,
Bjørn Larsen

Have you tried using TBlobField instead of TMemoField for the blob ?
Sorry, I don't have Delphi available right now to play around locally.

Related

Setting DateTime format in Delphi with Firedac compatible with BDE Application

I am migrating my application from Delphi2007 and BDE to Delphi 10.4 and Firedac. The new application is in testing, the old app is still there for backup, in case the new application fails.
So, I have 2 applications talking to the same database, one with Firedac, the other with BDE.
The following happens:
As soon as Firedac saves a DateTime field (date + time), that record can no longer be changed in the BDE application. (I use TQuery->DatasetProvide->TClientDataset, updatemode WhereAll, no persistent fields in the TQuery)
Probably, Firedac stores the time-part in a format that confuses the BDE/Datasetprovider.
Is it possible to make Firedac store time in a format the BDE does understand?
I know, the solution could be : adding persistent fields (> 100 tables), and setting the providerflag to pfInkey for all primary keys, and adding datasetproviders with updatemode "whereKeyOnly", but I do not want to change that much and spend so much time on the (very big) old (and soon to be deprecated) application that uses BDE.
I tried mappingrules in Firedac. I added 2 rules:
DateTimeStamp-> DateTime, DateTime -> DateTime.
For both rules I tested with values of PrecMax of 4,6,8. I thought maybe this way the time-value is stored with less precision, but this had no effect. Maybe some other value or mapping?
ADDITION
Editing the field with a dbExpress TSQLCOnnection instead of BDE works.
The default persistent field with TQuery is TDateTime, with dbExpress: TsqlTimeStamp. It seems like the "TDateTime" field is incompattible with values stored as a timestamp. The error is raized when apllying updates. Fetching the data is no problem.

AnyDAC (FireDAC) - Open transaction after TBlobField.GetAsString

at the moment we are migrating the database component of our Delphi7 application from the BDE components to the AnyDAC (FireDAC) Version 8.0.5 components.
The following prerequisites are given:
On our form we have one TADConnection, one TADQuery and one TADTable. The TADQuery is the MasterSource for the TADTable. No special changes have been made to the settings of the AnyDAC components, so the AutoCommit mode is active.
Furhtermore we have one TDBMemo on our form which is linked to an ftMemo field of the TADTable (Firebird FieldType = Blob / Size = 240 / Subtype = Text)
During the loading of the blob text field content (TBlobField.GetAsString) the TADTable starts automatically an transaction which would not committed.
Is this behavior normal? Do we have any possiblity to avoid this open transaction?
Please note, deactivating of the AutoCommit is no option at the moment.
Any help appreciated.
Yes, that is a normal behavior. So long you are not fetching BLOB data along with the detail tuple, AnyDAC starts an implicit transaction for fetching those BLOB data.

Firedac migration from BDE

My name is Stefano Fanti,I am a developer in Plexa.We are actually using your component ( FireDAC ) and I am contacting you in order to solve some
problems we have not been able to fix ourself.
In our company we decided to port a legacy 3-Tier DATASNAP application written on Delphi7 for the new environment Delphi XE7 , and we decided to use the new components library FireDAC too.
Our application is built in this way: a Client side using TClientDataSet directly connected to the Server side with TDataSetProvider/MIDAS and TTable TQuery TDatabase components (BDE)
We replaced BDE components with the related FireDAC ( FDConnection , FDTable and FDQuery ) without issues and we started testing thinking anyway it was not needed to perform it.
After some test , a couple of issues have arosen : the first problem is related to the modifications performed on DB ( MS SQL Server ) , the second is related the the reopening of the table after applying the modifications.
In our case , the RequestLive=True property ( default ) , does’nt allow to apply modifications ( Post/ApplyUpdates) to the Database.
Assigning RequestLive = False , we are able to apply modifications on all table’s records except the first, the last giving us the error .
The above anomaly have been verified on each Database table . However all database tables have the primary key defined properly.
Trying to use FireDAC Help I read the option RequestLive=False excludes fiMeta from Fetch,Options, preventing the component to use the primary key of the table, being otherwise seen correctly in any other case.
After several trials I found two configurations applied to the Server side, allowing us to achieve the result.
First configuration
FDTable.RequestLive= False
FDTable.UpdateMode = upWhereKeyOnly
with FProvider.DataSet.FieldByName (pkField) do
ProviderFlags: = ProviderFlags + [pfInKey];
Second configuration
FDTable.RequestLive= False
FDTable.UpdateMode = upWhereAll
TDataSetProvider.UpdateMode=upWhereAll
The above configurations give us the possibility to apply modifications to tables without errors , but nevertheless don’t allow us to solve the second problem : reopening of the tables for each operation. Indeed , the BeforeOpen and AfterOpen managers are executed each time.
What can I do to avoid the Table to be needless reopened after each modification ?
Are the configurations used to apply modifications correct , or maybe another solution exist allowing us to avoid code modifications causing us to lengthen development times ?
Thank you in advance for your help.
Best regards
Stefano Fanti

AnyDac aka FireDac cannot generate update query

I was using UniDac for a long time now and decided to move on to FireDac as it has good Asynch methods after moving on i saw that none of my data editing works anymore it gives me an error:
[FireDAC][Phys]-330. Cannot generate update query. Update table undefined.
What I am trying to do here is i have a TFDStoredProc component who gets all the data from the database and lets me edit it, with unidac I could easily edit the data without any problem like this:
StoredProc.Edit;
StoredProcCreatedID.Value := SomeValue;
StoredProc.Post;
and it worked, but with AnyDac it doesn't, I tried specifying manually the UpdateTable which leads to another problem:
[FireDAC][Phys][ODBC][Microsoft][SQL Server Native Client 11.0][SQL Server]Invalid column name 'CreatedID'.
I am using Microsoft SQL Server 2012 FireDac 8.0 and stored procedures for getting back results any ideas?
P.S.
The query looks like this
SELECT
CreatedBy as CreatedID,
usr.UserName as CreatedBy
FROM
Sales
LEFT JOIN
Users usr ON usr.ID = Sales.CreatedBy
it looks like the FireDac update builder doesn't recognize the aliases on the fields, any help would be appreciated.
Well i figured out what was the issue, it seems that if you specify a alias in the query for a field the Origin property will be set to the alias and not the real field i downloaded CNPack a must have for a delphi developer also its free, ran the component selector and changed all my aliased fields to their real fields and it works, but this is still a big issue in FireDac component because it doesnt recognize the aliased fields, lets hope it will be fixed in the future as to specify for every query what table it should update and what fields that just allot of work if you are migrating from a big project in my case 220+ stored procedures.

String Truncation on Transfer to ClientDataset

I'm using Firebird 2.1, DBExpress Driver from DevArt and Delphi 2010. Some of my reports that used to work with Delphi 2006 stopped working and produced an error message indicating that "arithmetic exception, numeric overflow, or string truncation" had occurred. The error occurred at this point in my code:
cds.Data := dsProvider.Data;
I found the place in my SQL statement that caused the error:
iif(ytd.hPayType <> -1,t.sCode, 'NET') sPayType
T.sCode is a Varchar(10) field. My conclusion is that the query returns data to the dsProvider and that when the dsProvider.Data is passed to the cds.Data, the cds component sets the field width based on the first value it receives. I get the same error message if I change the "iif" to a CASE statement. I managed to work around the issue by doing this:
CAST(iif(ytd.hPayType <> -1,t.sCode, 'NET') AS varchar(10)) sPayType
Since this used to work in Delphi 2006 without the CAST, I assume that the new behavior is due to an update to the TClientDataset. It would be nice to have the old, more forgiving behavior. Is there a way to configure the ClientDataset to accept this without a complaint or do I need to just tell my users to CAST on string results based on iif and CASE statements?
I used to work a lot with firebird in my last job, this error happens when you already have a large (length) varchar field value stored in the db and you are trying to "get" the string in delphi, try updating the value in the db to a smaller (length) varchar. I'm not sure if will work for you but give it a try.
Well, with a little more experience, it looks like I am seeing this truncation error show up consistently with the Delphi 2010 version of ClientDatasets. If I find a resolution that does not involve having to use CAST in the query, I will post it here. But for now, I am going to close this posting.

Resources