How to catch a TDBXException when using DBExpress - c++builder

Using a TClientDataSet and a connection to a remote MySQL server, using DBExpress and C++ Builder XE3.
A TDBGrid shows data from a particular table, navigated with a TDBNavigator.
When deleting a record in the grid, the deletion is first only reflected/recorded in the TClientDataSet and not on the server. The server side attempt to delete the record occur when 'ApplyUpdates' is called, as happens when clicking the 'ApplyUpdates' button on the navigator.
If the row have foreign keys pointing to data, a TDBXException is thrown, and the row is not deleted on the server (as it should be).
Question is, where to catch this exception when using the TDBNavigator?
Trying to catch in the navigators OnClick event don't work:
case TNavigateBtn::nbApplyUpdates:
try
{
Log(lWarning) << "About to delete a row";
}
catch(...)
{
}
break;
Any ideas?

Related

Why this code do not work in second time click button

I write this code for button click event . the first time I click the button every thing work correctly but when click for the second time on button it raise an error. whats the problem?
procedure TfrmMain.Button1Click(Sender: TObject);
var
B : Boolean;
begin
DM.tblTemp.DisableControls;
B:= DM.tblTemp.Locate('FoodName', DM.tblAsli.FieldByName('FoodName').AsString,[]) ;
if B then
begin
DM.tblTemp.Edit;
DM.tblTemp.FieldByName('Number').AsInteger:= DM.tblTemp.FieldByName('Number').AsInteger + 1;
DM.tblTemp.Post;
end
else
begin
DM.tblTemp.insert;
DM.tblTemp.FieldByName('FoodName').AsString := DM.tblAsli.FieldByName('FoodName').AsString;
DM.tblTemp.FieldByName('UnitPrice').AsInteger := DM.tblAsli.FieldByName('FoodPrice').AsInteger;
DM.tblTemp.FieldByName('Number').AsInteger := 1;
DM.tblTemp.Post;
end;
TotalPrice:= TotalPrice + DM.tblTemp.FieldByName('TotalPrice').AsInteger;
DM.tblTemp.EnableControls;
end;
the Error is
Row cannot be located for updating. Some values may have been changed
since it was last read
DM is data madual
tmbTbl is ADOTable
It is a pity you haven't said which DBMS you are using (e.g. Sql Server or MS Access,
nor told us a full list of the table's column types and indexes, if any.
The most likely answer to your q is that the variable B is set to False the first time
because the call to tblTemp.Locate fails to locate the Food name in question, so the Insert branch executes and the food's data is
added to the table but the second time the Edit branch executes and the error occurs,
though you have not said where, exactly. My guess would be on the call to .Post, because
the error message is one the ADO layer, which sits between the DBMS provider and your app,
emits when it attempts to post a change to the table but cannot identify which table row to update.
As I mentioned in a comment, the fix to this is usually at add a primary key index to the table, and I gather from your latest comment that this has succeeded for you. For the record and benefit of future readers it would be helpful if you could confirm which DBMS you are using and which Ole Driver you are using in your connection string.
Fwiw, I've tested your code using a table on MS Sql Server and MS Access and do not get the
error with either database.
Btw there is an obvious q, "How is it that tblTemp.Locate succeeds, but ADO is unable to
identify the correct record to post the update?" The answer is that tblTemp.Locate works in
a different way than identifying the relevant row to post the update.

How can I get the name of the database a DBExpress TSqlConnection is actually connected to?

I'm testing a quite old Delphi 6 application and would like to display the database name the TSqlConnection is actually connected to, so I can see quickly if I'm connected to the test or production database.
In sqlconnections.ini, the app has a connection named 'Vienna' to a Firebird database defined like this:
Database=192.168.1.15:ProductionDB (it's an alias)
and I've replaced that for testing purposes with
Database=192.168.1.15:TestDB.
But I've seen that just accessing the TSqlConnection's Params-List and there the value of 'Database' does not work. This value is always set the same as it is in design mode.
How can I find out which database (which Firebird alias in my case) the TSqlConnection is actually connected to?
monitoring tables were introduced into FB 2.1.x :-)
So try
select MON$DATABASE_NAME from MON$DATABASE
Or try
select MON$ATTACHMENT_NAME from MON$ATTACHMENTS
where MON$ATTACHMENT_ID = CURRENT_CONNECTION
See info at
c:\Program Files (x86)\Firebird\Firebird_2_1\doc\README.monitoring_tables.txt
http://firebirdsql.su/doku.php?id=mon_database via www.translate.ru
https://dba.stackexchange.com/questions/29919/firebird-monitoring-tables
http://www.upscene.com/documentation/fbtm2/index.html?dm_monitoringtables.htm
http://www.firebirdsql.org/file/community/conference-2014/pcisar/#1
When SQLConnection.Params property is empty Params.Values['Database'] return empty string even when BeforeConnect or AfterConnect events is fired .
You can use TSQLConnection.OnLogin event.
For example :
procedure TForm11.SQLConnection1Login(Database: TSQLConnection;
LoginParams: TWideStrings);
var
i : integer;
begin
//Show all params
for I := 0 to LoginParams.Count - 1 do
ShowMessage(LoginParams[i]);
// Show database
ShowMessage(LoginParams.Values['Database']);
end;
Use the OnLogin event to assign values to the User_Name, Password, and
Database parameters immediately before TSQLConnection attempts to
connect to the database server. OnLogin only occurs if the LoginPrompt
property is true. If LoginPrompt is true but there is no OnLogin event
handler, a default login dialog appears in which the user can enter a
user name and password. The connection fails if correct values for the
user name and password are not supplied in the dialog or by the
OnLogin event handler.
Source

Delphi Error: 'Dataset not in edit or insert mode'

So, I Googled the following, but cannot seem to find an answer.
I've got a few Access tables that I am trying to update from Delphi.
The one table updates perfectly, so I know my database connection is active (the connection is set when the main form loads).
The problem is the second table. I keep on getting the error: "Dataset not in edit or insert mode".
In the formshow procedure I've got the following code:
//Connect to the individuals details table
dmoDonations.tblInd.Connection:= dmoDonations.adoDonations;
dmoDonations.tblInd.ReadOnly:= False; //Enable read / write
dmoDonations.tblInd.Active:= False;
dmoDonations.tblInd.TableName:='Individuals';
dmoDonations.tblInd.Active:= True;
dmoDonations.tblInd.Append; //Insert new record
dmoDonations.cdsInd.Open;
dmoDonations.cdsInd.Active:= True;
dmoDonations.cdsInd.ReadOnly:= False;
dmoDonations.cdsInd.Refresh;
And the rest of the code to update the table is under the updateButtonClick procedure:
dmoDonations.tblInd.Insert; //Insert new record
dmoDonations.tblInd['Name']:= edtName.Text;
dmoDonations.tblInd['Address1']:= edtAddress1.Text;
dmoDonations.tblInd['Address2']:= edtAddress2.Text;
dmoDonations.tblInd['Address3']:= edtAddress3.Text;
dmoDonations.tblInd['Phone']:= edtPhone.Text;
dmoDonations.tblInd['Email']:= edtEmail.Text;
dmoDonations.tblInd.Post; //Saves new records
It's at the last line where the error pops up when I step through the code. Why would this error occur even though the table is open and active and I've inserted / appended the table (have tried both options in both sections of code)?

Msacces stored query and delphi using ado error

I have prepared this query in access and it is working ok.
SELECT Kod, Unvan, CepTel, Telefon, (SELECT Sum(Borc.Tutar) from borc
where carikod=kod) AS BorcTutar, (SELECT Sum(Alacak.Tutar) from Alacak
where carikod=kod) AS AlacakTutar
FROM cari;
But when want to use query in delphi i have to use serverside corsorlocation and static cursor.
Then delphi throw an exception and says "e-fail" , "invalid argument" and diffrent kind of messages when i change the cursor locations and types..
It is working wit clientside cursor but return 0 for sum()..
How to use correctly this query...
I have converted the "amount" fields the currency, then delphi choose correct type for them (tbcdfield beside tintegerfield)....
report is working now

Corrupting Access databases when inserting values

Recently, a program that creates an Access db (a requirement of our downstream partner), adds a table with all memo columns, and then inserts a bunch of records stopped working. Oddly, there were no changes in the environment that I could see and nothing in any diffs that could have affected it. Furthermore, this repros on any machine I've tried, whether it has Office or not and if it has Office, whether it's 32- or 64-bit.
The problem is that when you open the db after the program runs, the destination table is empty and instead there's a MSysCompactError table with a bunch of rows.
Here's the distilled code:
var connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=corrupt.mdb;Jet OLEDB:Engine Type=5";
// create the db and make a table
var cat = new ADOX.Catalog();
try
{
cat.Create(connectionString);
var tbl = new ADOX.Table();
try
{
tbl.Name = "tbl";
tbl.Columns.Append("a", ADOX.DataTypeEnum.adLongVarWChar);
cat.Tables.Append(tbl);
}
finally
{
Marshal.ReleaseComObject(tbl);
}
}
finally
{
cat.ActiveConnection.Close();
Marshal.ReleaseComObject(cat);
}
using (var connection = new OleDbConnection(connectionString))
{
connection.Open();
// insert a value
using (var cmd = new OleDbCommand("INSERT INTO [tbl] VALUES ( 'x' )", connection))
cmd.ExecuteNonQuery();
}
Here are a couple of workarounds I've stumbled into:
If you insert a breakpoint between creating the table and inserting the value (line 28 above), and you open the mdb with Access and close it again, then when the app continues it will not corrupt the database.
Changing the engine type from 5 to 4 (line 1) will create an uncorrupted mdb. You end up with an obsolete mdb version but the table has values and there's no MSysCompactError. Note that I've tried creating a database this way and then upgrading it to 5 programmatically at the end with no luck. I end up with a corrupt db in the newest version.
If you change from memo to text fields by changing the adLongVarWChar on line 13 to adVarWChar, then the database isn't corrupt. You end up with text fields in the db instead of memo, though.
A final note: in my travels, I've seen that MSysCompactError is related to compacting the database, but I'm not doing anything explicit to make the db compact.
Any ideas?
As I replied to HasUp:
According MS support, creation of Jet databases programmatically is deprecated. I ended up checking in an empty model database and then copying it whenever I needed a new one. See http://support.microsoft.com/kb/318559 for more info.

Resources