|
|
Home » U++ Library support » U++ SQL » ODBC Assertion failed
ODBC Assertion failed [message #55812] |
Thu, 17 December 2020 11:01  |
Giorgio
Messages: 218 Registered: August 2015
|
Experienced Member |
|
|
Hi there,
I have an application that has to insert some data on a Microsoft SQL Server db.
When the query runs without error the application is ok, the problem is when the query fails for some reason: in that case the application crashes.
This is what I found in the log:
ERROR [Microsoft][ODBC SQL Server Driver][SQL Server]Violation of PRIMARY KEY constraint 'PK_RIG'. Cannot insert duplicate key in object 'dbo.DOROW'. The duplicate key value is [...]
****************** ASSERT FAILED: Assertion failed in C:\Users\GIRU1\ToolsBox\upp-2020.1\uppsrc\ODBC\ODBC.cpp, line 215
tlevel >= 0
This is the code that crashes:
bool InsertDoument(ValueMap * vm){
Sql query(my_mssql_db);
query.ClearError();
query.Begin();
try{
query * Insert(My_mssql_table)(*vm);
} catch(SqlExc) {
ErrorOK(query.GetLastError());
}
if(query.WasError()){
query.Rollback();
return false;
}
query.Commit();
return true;
}
Thanks for any hint!
gio
|
|
|
Re: ODBC Assertion failed [message #55813 is a reply to message #55812] |
Thu, 17 December 2020 14:09   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
Giorgio wrote on Thu, 17 December 2020 11:01if (query.WasError())
I'm not sure that you should use 2 error checks - both "try_catch" & "if (query.WasError())"... I think WasError can be enough & you'd better try to do the whole necessary stuff here in this scope (including the one that you're trying to do in catch)... then "try_catch" seems unneeded for me...
I'm not sure but it seems to be excessive error checks when using both... because in catch-scope you are not correctly closing your connection to process the error that arrised, but still continue to utilize it (connection) for error checks again... imho
Best regards.
[Updated on: Fri, 18 December 2020 06:32] Report message to a moderator
|
|
|
|
Re: ODBC Assertion failed [message #55815 is a reply to message #55812] |
Thu, 17 December 2020 15:06   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
Giorgio wrote on Thu, 17 December 2020 11:01Violation of PRIMARY KEY
In any case it is the problem that should be solved at Server-side & SQL-statement better... before insertion check for Uniqueness in some Join or take Distinct Group_By - to assure that rows to be inserted are really unique - as PKs ought to be...
If I had a chance to meet some duplication of PKs - I would first make Query for them (with a help of Self-Join), to understand what rows are really problematic & how to correct input data, then make necessary corrections either manually or in code - to have correct data, filtered from duplications, and then try again to insert into DB...
SQL language has pretty enough stuff to deal with such situations - e.g. Triggers...
An attempt to insert 2 identical PKs into DB should be filtered somehow in the Query itself, not in application language... though of course the last is also possible - to check duplications in C++ before Insert Into DB - but it is not very convenient...
Best regards.
[Updated on: Thu, 17 December 2020 15:11] Report message to a moderator
|
|
|
|
Re: ODBC Assertion failed [message #55818 is a reply to message #55812] |
Thu, 17 December 2020 17:44   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
well, your disagreement also seems reasonable...
Giorgio wrote on Thu, 17 December 2020 11:01upp-2020.1\uppsrc
... additional check needed from upp-team who use this version... I cannot help with any other suggestions because am using older version & cannot reproduce the situation...
with sqlite3 WasError() catches PK-duplication error & after PromptOK-notification within it (that I use to see GetErrorStatement) normal return from WasError()-scope & from function without crash of app...
Best regards.
[Updated on: Thu, 17 December 2020 17:49] Report message to a moderator
|
|
|
Re: ODBC Assertion failed [message #55823 is a reply to message #55818] |
Fri, 18 December 2020 06:26   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
BTW, I can just suggest to make a couple of experiments:
1) try to log your queries with something like (but about your ms sql server)
sqlite3.Open(db)
#ifdef _DEBUG
sqlite3.SetTrace(); //logging queries
#endif
& without Commit & Rollback... AFAIK, such command is being self-rollbacked automatically in the case of error or commited automatically if no errors - in ms sql server - but I have no chance to check it in ms sql server
// initialize transaction
BEGIN TRAN;
// transaction
INSERT INTO sales
VALUES ('7896', 'JR3435', 'Oct 28 1997', 25, 'Net 60', 'BU7832');
2) I'm not sure, that having duplicated PKs the query starts anyway, therefore I'm not sure that you have the right to do Rollback when this error arrised...
therefore you can try just SQL-statement to .Execute, expressing your sql-command in sql-string, not u++ method Insert... something like this - that is doing rollback ONLY IF @@TRANCOUNT > 0
BEGIN TRY
BEGIN TRANSACTION
exec( @sqlHeader)
COMMIT
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK
END CATCH
or check this count in U++ somehow, before rollback - though it seems meaningless in the case of error... If you'd had several queries - you'd had something to rollback if previous queries already done... but in a single Insert failed - nothing to Rollback... imho
Best regards.
[Updated on: Fri, 18 December 2020 06:53] Report message to a moderator
|
|
|
|
|
|
Re: ODBC Assertion failed [message #55830 is a reply to message #55824] |
Fri, 18 December 2020 14:02   |
mr_ped
Messages: 826 Registered: November 2005 Location: Czech Republic - Praha
|
Experienced Contributor |
|
|
Giorgio wrote on Fri, 18 December 2020 08:26I've found out that the problem arises only in debug mode. The problem is the ASSERT at line 200 and 215 in ODBC/ODC.cpp. I can live without having the capability to debug that part of code, although it's very handy when there are issues (a problem with that part of the code was the reason I turned on the debugger in the first place).
Usually ASSERT compiles to nothing in release, and to debug check under debug.
So "arises only in debug mode" means that you see the warning in debug mode, but in release the same condition, which would trigger assert, does nothing and continues further.
ASSERT usually ensures conditions which "must be true" (and there is no need to check it at runtime) and the code after them usually is written in such a way that it may often crash hard if the condition is false.
So you get assert warning only in debug mode, but most likely the real problem is happening in release too, it's just not catched early by ASSERT, but causes havoc further down the line. In some situations you may be lucky that the code after is robust enough to survive even when condition is false, and the assert is rather just information that something is seriously broken in the code, way beyond the author expectations.
[Updated on: Fri, 18 December 2020 14:03] Report message to a moderator
|
|
|
Re: ODBC Assertion failed [message #55842 is a reply to message #55830] |
Mon, 21 December 2020 09:54   |
Giorgio
Messages: 218 Registered: August 2015
|
Experienced Member |
|
|
Hi,
I reviewed my code, but I actually cannot see anything terrible. I have innumerable queries in PostgreSQL that is the rdbms that I currently use, previously I used MySql so I wrote a lot queries with that also, have also a few in sqlite... never a problem. The structure of the code is in my first post: it seems to me very simple and basic. I also tried different combinations of try/catch and .WasErrors() but the behaviour is also the same. Maybe it's the way I open the connection to the db?
(mymssql_db is a private memeber of the class and its type is MSSQLSession).
bool OpenMSSqlDB(){
String username = "sa";
String pwd = "mypassword";
String dbname = "MYDBNAME";
String server = "servername\\instancename";
String cs = "Driver={SQL Server};Server=" + server +
";UID=" + username + ";PWD=" + pwd + ";Database=" + dbname + ";";
if(!mymssql_db.Connect(cs))
{
string err="Unable to connect to MSSql database due to the following error: " + mymssql_db.GetLastError().ToStd();
this->err_messages->push_back(err);
return false;
}
mymssql_db.ThrowOnError();
mymssql_db.LogErrors();
mymssql_db.SetTrace();
return true;
}
So if you could give me some hints about some tests to perform or what to look for in my code I could really use it.
Thanks,
gio
[Updated on: Mon, 21 December 2020 09:55] Report message to a moderator
|
|
|
Re: ODBC Assertion failed [message #55844 is a reply to message #55812] |
Mon, 21 December 2020 15:33   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
was this correct in your whole code?
Quote:SQL = myDB;
Sql query(myDB);
the insertion below is working for me in Sqlite3 - try to adopt the code to your MS_SQL_Server_connection (your Commit, Rollback & WasError() are included in this code, I just can not check for ms_sql_server & therefore cannot provide adopted example)... but such is my view on insertion
#include <Core/Core.h>
#include <plugin/sqlite3/Sqlite3.h>
using namespace Upp;
CONSOLE_APP_MAIN
{
Cout() << "Start" << EOL;
Sqlite3Session myDB; // <<<<<<<<<<<<<< ADOPT TO YOUR MS_Sql_Server.....
if(!myDB.Open(ConfigFile("DATA.db"))) {
LOG("Can't create or open database file\n");
return;
}
#ifdef _DEBUG
myDB.SetTrace();
#endif
SQL = myDB;
// ======================= initial data
String s = "[{\"A\":\"valA1\", \"B\":\"valB1\"}, {\"A\":\"valA2\", \"B\":\"valB2\"}]";
ValueMap js=ParseJSON(s); // frankly speaking ValueArray should be perhaps, but it works for me...
int jsz=js.GetCount();
// ======================= create tbl
SQL.Execute("drop table IF EXISTS tbl;");
SQL.Execute("create table IF NOT EXISTS tbl (A STRING , B STRING, PRIMARY KEY (A));");
// ======================= insert into tbl
Sql query(myDB); // (my_db)
query.SetStatement("INSERT INTO tbl ( A, B) VALUES ( ?, ?) ");
// initialize transaction
query.Begin();
// loop to insert rows
for(size_t i = 0; i < jsz; i++) {
query.SetParam(0,~js[i]["A"]);
query.SetParam(1,~js[i]["B"]);
query.Execute();
}
// error behavior
if(query.WasError()){
Cout() << query.GetLastError();
query.Rollback();
return; // false;
}
//Save data & unlock db
query.Commit();
Cout() << "Done" << EOL;
// ======================= select to console_view
if (query.Execute("SELECT * FROM tbl"))
{
Cout() << "Call succeeded" << EOL;
for (int i = 0; i < query.GetColumnCount(); ++i) {
Cout() << Format("%d: %s", i, query.GetColumnInfo(i).name) << EOL;
}
while (query.Fetch()) {
Cout() << query[0] << " ; " << query[1] << EOL;
}
}
else
{
Cout() << "Call failed" << EOL;
Cout() << SQL.GetLastError() << EOL;
}
}
if you put "valA1" to both A-key values in json-string -- you will catch
Quote:SQL logic error
p.s.
I don't know whether SqlMassInsert will be quicker, but using Transactions gives the possibility for Rollback - I am not sure about this possibility in SqlMassInsert, perhaps it is being done automatically for this class - in LOG should be seen, - but I didn't check SqlMassInsert& UseTransaction(bool b = true) == testing needed to compare the speed of 2 approaches (my & SqlMassInsert)
Wish you good luck if my code could be helpful for you... or somebody can notice some mistakes with a fresh_eye
Best regards.
[Updated on: Fri, 01 January 2021 17:08] Report message to a moderator
|
|
|
Re: ODBC Assertion failed [message #55847 is a reply to message #55830] |
Tue, 22 December 2020 11:44   |
Giorgio
Messages: 218 Registered: August 2015
|
Experienced Member |
|
|
mr_ped wrote on Fri, 18 December 2020 14:02Giorgio wrote on Fri, 18 December 2020 08:26I've found out that the problem arises only in debug mode. The problem is the ASSERT at line 200 and 215 in ODBC/ODC.cpp. I can live without having the capability to debug that part of code, although it's very handy when there are issues (a problem with that part of the code was the reason I turned on the debugger in the first place).
Usually ASSERT compiles to nothing in release, and to debug check under debug.
So "arises only in debug mode" means that you see the warning in debug mode, but in release the same condition, which would trigger assert, does nothing and continues further.
ASSERT usually ensures conditions which "must be true" (and there is no need to check it at runtime) and the code after them usually is written in such a way that it may often crash hard if the condition is false.
So you get assert warning only in debug mode, but most likely the real problem is happening in release too, it's just not catched early by ASSERT, but causes havoc further down the line. In some situations you may be lucky that the code after is robust enough to survive even when condition is false, and the assert is rather just information that something is seriously broken in the code, way beyond the author expectations.
I think I found the problem. In the ODBC there is a member called tmode of type "TransactionMode". TransactionMode can be NORMAL or IMPLICIT. There is also the related method SetTransactionMode to modify tmode. For some reason it was set to NORMAL and that caused the issue. Setting it to IMPLICT fixed the problem.
Unfortunately I did not found any reference to SetTransactionMode in the forum so the only way to understand the problem was inspecting the ODBC.h and ODBC.cpp code. The problem was specifically related to MSSQLSession, so nothing in the query itself was wrong and changing it would not have helped. I do not think that my code was "seriously broken in the code, way beyond the author expectations" and I do think that who wrote that piece of code could have easily given some hint about the origin of the problem.
|
|
|
Re: ODBC Assertion failed [message #55850 is a reply to message #55847] |
Tue, 22 December 2020 18:22   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
Giorgio wrote on Tue, 22 December 2020 11:44mr_ped wrote on Fri, 18 December 2020 14:02Giorgio wrote on Fri, 18 December 2020 08:26I've found out that the problem arises only in debug mode. The problem is the ASSERT at line 200 and 215 in ODBC/ODC.cpp. I can live without having the capability to debug that part of code, although it's very handy when there are issues (a problem with that part of the code was the reason I turned on the debugger in the first place).
Usually ASSERT compiles to nothing in release, and to debug check under debug.
So "arises only in debug mode" means that you see the warning in debug mode, but in release the same condition, which would trigger assert, does nothing and continues further.
ASSERT usually ensures conditions which "must be true" (and there is no need to check it at runtime) and the code after them usually is written in such a way that it may often crash hard if the condition is false.
So you get assert warning only in debug mode, but most likely the real problem is happening in release too, it's just not catched early by ASSERT, but causes havoc further down the line. In some situations you may be lucky that the code after is robust enough to survive even when condition is false, and the assert is rather just information that something is seriously broken in the code, way beyond the author expectations.
I think I found the problem. In the ODBC there is a member called tmode of type "TransactionMode". TransactionMode can be NORMAL or IMPLICIT. There is also the related method SetTransactionMode to modify tmode. For some reason it was set to NORMAL and that caused the issue. Setting it to IMPLICT fixed the problem.
Unfortunately I did not found any reference to SetTransactionMode in the forum so the only way to understand the problem was inspecting the ODBC.h and ODBC.cpp code. The problem was specifically related to MSSQLSession, so nothing in the query itself was wrong and changing it would not have helped. I do not think that my code was "seriously broken in the code, way beyond the author expectations" and I do think that who wrote that piece of code could have easily given some hint about the origin of the problem.
Sorry for the late reply, only now I have checked all details.
The ASSERT should basically mean that there is mismatch between Begin and Commit/Rollback pairs.
NORMAL transaction mode means you are using Begin/Commit/Rollback. Without Begin, there is commit after each statement. Transactions can be nested (it that case, only top-level transaction is relevant).
In IMPLICIT mode, each commit or rollback starts another transaction. Begin is the same as commit, mismatch between Begin/Commit is ignored. That is why you are not seeing the problem with IMPLICIT mode...
That said, I cannot construct a scenario which would lead to failure you describe. Would it be possible to insert DDUMP(tlevel) before both ASSERTs? (and post here the result...)
Mirek
|
|
|
Re: ODBC Assertion failed [message #55851 is a reply to message #55850] |
Tue, 22 December 2020 18:49   |
 |
mirek
Messages: 14255 Registered: November 2005
|
Ultimate Member |
|
|
One little issue: You are supposed to use Begin/End/Commit with your session, not query - that is deprecated. But in fact, the result should be the same (it just calls GetSession().Begin().. etc...)
For what is worth, I have altered SQL_MSSQL reference example to check the issue:
#include "app.h"
#include <Sql/sch_schema.h>
#include <Sql/sch_source.h>
using namespace Upp;
CONSOLE_APP_MAIN
{
MSSQLSession mssql;
if(!mssql.Connect("Driver={SQL Server Native Client 11.0};Server=localhost;Database=master;Trusted_Connection=Yes;")) {
Cout() << "Connect failed: " << mssql.GetLastError() << '\n';
return;
}
SQL = mssql;
SqlSchema sch(MSSQL);
StdStatementExecutor se(SQL.GetSession());
All_Tables(sch);
ODBCPerformScript(sch.Upgrade(), se);
ODBCPerformScript(sch.Attributes(), se);
#ifdef _DEBUG
mssql.SetTrace();
mssql.LogErrors();
mssql.ThrowOnError();
#endif
SQL.Begin();
try {
for(int i = 0; i < 10; i++)
SQL * Insert(TEST)(ID, i)(TEXT, String('A' + i, 1));
}
catch(SqlExc e)
{
DDUMP(e);
}
if(SQL.WasError()) {
DLOG("There was ERROR!");
SQL.Rollback();
}
else
SQL.Commit();
S_TEST tst;
Sql sql;
sql * Select(tst).From(TEST);
while(sql.Fetch(tst))
Cout() << tst.ID << ", " << tst.TEXT << '\n';
}
and everything works as expected...
Mirek
|
|
|
Re: ODBC Assertion failed [message #55855 is a reply to message #55851] |
Wed, 23 December 2020 06:08   |
JeyCi
Messages: 67 Registered: July 2020
|
Member |
|
|
mirek wrote on Tue, 22 December 2020 18:49One little issue: You are supposed to use Begin/End/Commit with your session, not query - that is deprecated.
thanks for corrections of my view!
then we can use "try-catch" for query/transaction & WasError()-catching for the session, as I can see... will remember
& thanks to Giorgio for such useful question
Best regards.
[Updated on: Wed, 23 December 2020 09:47] Report message to a moderator
|
|
|
Re: ODBC Assertion failed [message #56109 is a reply to message #55850] |
Wed, 27 January 2021 16:44   |
Giorgio
Messages: 218 Registered: August 2015
|
Experienced Member |
|
|
Hello,
I made a lot of tests in the last weeks and I still cannot wrap my head around this error.
To begn with, I had some issues with DDUMP: if I put that before the assert and I try to compile in release mode I got "error C2018: unknown character '0x40'". So I used RDUMP in release. In debug mode DDUMP is ok.
Anyway, I noticed in the log "tlevel = 0" and just after that "tlevel = -1" so inspecting closely the code I found this in the destructor of the class:
if(my_mssql_db.IsOpen()){
my_mssql_db.Commit();
my_mssql_db.Close();
}
Actually, that extra .Commit() was wrong (there was no matching between the .Begin and the .Commit/.Rollback) and after I removed it the "tlevel = -1" disappeared... but the application crashed anyway.
So I tried something different. The code I posted initially is actually a simplified version of my code. What I'm doing is inserting a header/body document, so I have a query that insert the header in a table and after that a for cycle for the body in a different table. Initially I used just one Sql object both for the header and the body, so I tried to use two different Sql objects, one for the body and one for the header:
bool InsertDocument(ValueMap * header, vector<vm*> * rows){
Sql query_header(my_mssql_db);
query_header.ClearError();
Sql query_body(my_mssql_db);
query_body.ClearError();
query_header.Begin();
query_body.Begin();
try{
query_heder * Insert(My_mssql_header_table)(*header);
} catch(SqlExc) {
ErrorOK(query_header.GetLastError());
}
for(vector<vm*>::iterator it = rows->begin(); it != rows->end(); ++it) {
try{
query_body * Insert(My_mssql_body_table)(*it);
} catch(SqlExc) {
ErrorOK(query_body.GetLastError());
}
}
if(query_header.WasError() || query_body.WasError(){
query_body.Rollback();
query_header.Rollback();
return false;
}
query_header.Commit();
query_body.Commit();
return true;
}
After a couple of tests it seemed to work, but in the end also this approach led to crashes. At the end I decided to scrap the Commit altogether, so each insert it's by itself. After a couple of week of usage I got no crashes. This approach can lead to some inconsistencies (e.g. an header without a body), but luckily enough this is a quite isolated part of the application, so I can manage manually this kind of situation.
What baffles me is that - AFAIK - using a transaction to bundle together a bunch of insert is perfectly fine (it's actually the best solution because in case of problem you rollback the entire set of instructions - both the insert in the header and those in the body), so I cannot understand why using "isolated" insert is working while Commit leads to crashes.
Regards,
gio
|
|
|
|
Re: ODBC Assertion failed [message #56113 is a reply to message #56110] |
Thu, 28 January 2021 09:26   |
Giorgio
Messages: 218 Registered: August 2015
|
Experienced Member |
|
|
mirek wrote on Wed, 27 January 2021 17:08Giorgio wrote on Wed, 27 January 2021 16:44Hello,
bool InsertDocument(ValueMap * header, vector<vm*> * rows){
Sql query_header(my_mssql_db);
query_header.ClearError();
Sql query_body(my_mssql_db);
query_body.ClearError();
query_header.Begin();
query_body.Begin();
This is really quite ugly code: Transaction is associated with SqlSession, so the second begin starts the second level.
I agree it was one desperate attempt, at the end I removed the "double" session...
[Updated on: Thu, 28 January 2021 09:27] Report message to a moderator
|
|
|
Goto Forum:
Current Time: Sat Apr 26 13:25:47 CEST 2025
Total time taken to generate the page: 0.02417 seconds
|
|
|