updating database blobs with otl crashes - c++

I'm writing a simple application to correct a certain byte in a binary blob that's stored in a database. I use OTL to connect my C++ program to the database.
Reading the data and manipulation works fine, but when I want to write it back to the database, the program dies.
The code:
try
{
std::string updateQuery = "UPDATE tbtptemplates "
" SET tptemplate=:tp<BLOB> "
"WHERE afisid=:aid<INT>";
otl_long_string blob(&stp(), theSizeOfBlob);
blob.set_len(theSizeOfBlob);
otl_stream str(1, updateQuery.c_str(), theDbConnection);
str.set_lob_stream_mode(true);
str.set_commit(0);
otl_lob_stream lob;
lob.set_len(theSizeOfBlob);
str << lob;
str << theCurrentAfisId;
lob << blob;
lob.close();
}
catch (const otl_exception &oe)
{
std::cerr << oe.msg;
throw std::runtime_error("could not write to database");
}
I spied at Sourceforge for an example.
I create an otl_long_string that takes the data.
Then I create an otl_stream and bring together the SQL statement and the database connection.
I use an otl_lob_stream to provide the binary data to the otl_stream.
Streaming of the blob data to the otl_stream works fine. But when I hand over the id to the stream, the process dies.
This is the killer instruction:
str << theCurrentAfisId;
it is a simple int-variable that I hand over.
The effect is very funny: the process doesn't die completely, only the call stack below the current method is gone.
This is the call stack before the statement:
Thread #1 [fix_stp] 10307 [core: 7] (Suspended : Breakpoint)
Drm::TPFixer::DatabaseConnector::writeDB() at DatabaseConnector.cpp:224 0x40b565
Drm::TPFixer::DatabaseConnector::fixImpressiontype() at DatabaseConnector.cpp:139 0x40b516
Drm::TPFixer::SuperTemplateManager::fixImpressiontype() at SuperTemplateManager.cpp:67 0x4074e3
main() at main.cpp:51 0x40477b
and this is the complete stack in the very moment after the instruction:
Thread #1 [fix_stp] 10307 [core: 7] (Running : Step)
Drm::TPFixer::DatabaseConnector::writeDB() at DatabaseConnector.cpp:240 0x40b6b2
I tried to debug the otl. It seems that the otl finds that it's got all required parameters and starts to run. In that moment it crashes.
The environment that I use:
- OTL 4.0
- CentOS Linux, kernel 3.10.0-327.22.2.el7.x86_64
- gcc-Version 4.8.5
- Oracle 11g
Does anybody have an idea?

Related

Calling PLsql script with an anonymous PL SQL block from SOCI

I'm searching for a way to call an anonymous PLsql block through SOCI. The data transfer takes place through a refcursor that was previously created as a variable in the script:
variable rc refcursor
declare
v_obj_id number(4,0) := 1;
v_obj_def varchar(30);
v_obj_type number := 1;
begin
open :rc for
select v_obj_id, OBJ_DEF_ID
from MY_OBJECT_DEFS
where OBJECT_TYPE = v_obj_type;
end;
I need to read the refcursor from my application to retrieve the data. I tried to execute the above through a soci::statement but it gives me the error: ORA-24333: zero iteration count. The PLsql script works fine when executed in SqlPlus.
How can I make the connection between the statement and the
refcursor rc? Should I use some other SOCI construct (other than statement) for this purpose?
I understand there are two instructions in the above
script; (i. the refcursor creation, ii. the anonymous PLsql block
itself). I'm not sure whether its possible to call multiple
instructions in a single SOCI statement. Can this be confirmed?
Following is the what I tried. The sSQL contains the above PLsql script:
dbConn.open("...");
int iObjId;
std::string iObjDefId;
soci::indicator ind_iObjId = soci::i_ok,
ind_iObjDefId = soci::i_ok;
soci::statement stmt(dbConn);
stmt.alloc();
stmt.prepare(sSQL);
stmt.exchange(soci::into(iObjId, ind_iObjId));
stmt.exchange(soci::into(iObjDefId, ind_iObjDefId));
stmt.define_and_bind();
stmt.execute(false);
while (stmt.fetch())
{
if (soci::i_ok == ind_iObjId)
std::cout << "Obj ID: " << iObjId << std::endl;
if (soci::i_ok == ind_iObjDefId)
std::cout << "Obj Def ID: " << iObjDefId << std::endl;
}
EDIT: I'm using Oracle 11g
The statement variable rc refcursor is neither SQL nor PL/SQL but part of Oracle's SQL*Plus command-line utility and compatible third party products. I don't know C++ but presumably you would need to define a ref cursor object in the host program.
If this is not feasible, and you are on Oracle 12.1 or later, it's possible that you could use an implicit result set construction, along the lines of
declare
rc sys_refcursor;
begin
open rc for select * from dual;
dbms_sql.return_result(rc);
end;
as discussed in Is it possible to output a SELECT state from a PL/SQL block?

ubuntu server pipeline stop process termination when the first exit

The situation is: I have an external application so I don't have the source code and i can't change it. While running, the application writes logs to the stderr. The task is to write a program that check the output of it and separate some part of the output to other file. My solution is to start the app like
./externalApp 2>&1 | myApp
the myApp is a c++ app with the following source:
using namespace std;
int main ()
{
string str;
ofstream A;
A.open("A.log");
ofstream B;
B.open("B.log");
A << "test start" << endl;
int i = 0;
while (getline(cin,str))
{
if(str.find("asdasd") != string::npos)
{
A << str << endl;
}
else
{
B << str << endl;
}
++i;
}
A << "test end: " << i << " lines" << endl;
A.close();
B.close();
return 0;
}
The externalApp can crash or be terminated. A that moment the myApp gets terminated too and it is don't write the last lines and don't close the files. The file can be 60Gb or larger so saving it and processing it after not a variant.
Correction: My problem is that when the externalApp crash it terminate myApp. That mean any code after while block will never run. So the question is: Is there a way to run myApp even after the externalApp closed?
How can I do this task correctly? I interesed in any other idea to do this task.
There's nothing wrong with the shown code, and nothing in your question offers any evidence of anything being wrong with the shown code. No evidence was shown that your logging application actually received "the last lines" to be written from that external application. Most likely that external application simply failed to write them to standard output or error, before crashing.
The most likely explanation is that your external application checks if its standard output or error is connected to an interactive terminal; if so each line of its log message is followed by an explicit buffer flush. When the external application's standard output is a pipe, no such flushing takes place, so the log messages get buffered up, and are flushed only when the application's internal output buffer is full. This is a fairly common behavior. But because of that, when the external application crashes its last logged lines are lost forever. Because your logger never received them. Your logger can't do anything about log lines it never read.
In your situation, the only available option is to set up and connect a pseudo-tty device to the external application's standard output and error, making it think that's connected to an interactive terminal, while its output is actually captured by your application.
You can't do this from the shell. You need to write some code to set this up. You can start by reading the pty(7) manual page which explains the procedure to follow, at which point you will end up with file descriptors that you can take, and attach to your external application.
If you want your program to cleanly deal with the external program crashing you will probably need to handle SIGPIPE. The default behaviour of this signal is to terminate the process.
So the problem was not that when the first element of the pipe ended it terminate the second. The real problem was that the two app with pipes launched from bash script and when the bash script ended it terminated all of it child process. I solved it using
signal(SIGHUP,SIG_IGN);
that way my app executed to the end.
Thank you for all the answer at least I learned lot about the signals and pipes.

ORACLE bulk insert based on SQL

Ich have to shuffle a lot of data data from an application into an ORACLE 11g database. To execute SQL from within C++ I use to employ the following scheme, using bare SQL together with the Poco::Data framework and an ODBC connection to my database:
// get session from ODBC session pool
Session session = moc::SessionPoolMOC::get();
// prepare a statement as QString
QString q = ("INSERT INTO MOC_DATA_CONCENTRATOR"
"("
"EQUIPMENT_INSTANCE_ID, "
"STATION_NAME, "
"DATA_SRC, "
"ORG_ID)"
"values (%1, '%2', '%3', %4);"
);
/*
there would be also prepared statements, but I think that is not the
topic now...
*/
// set parameters within string from passed object 'info'
q = q.arg(info.equipment_instance_id); /* 1 */
q = q.arg(info.station_name.toUtf8().constData()); /* 2 */
q = q.arg(info.data_src.toUtf8().constData()); /* 3 */
q = q.arg(info.org_id); /* 4 */
// prepare statement
Statement query(session);
query << q.toUtf8().constData();
try
{
// execute query
query.execute();
}
catch (...)
{
...
}
I'm aware, that this is a very low level approach, but it worked really fine for all situations I encountered so far...
The problem is, that I have now a lot of data (about 400,000 records) to fill into one table. Data is available as different C++ objects, stored in a Qt-List. My naive approach is to call this code sequence for each object to insert. This works fine, but turns out to be quite slow (taking about 15 minutes or so). I asked around, and was told to better use a so called "bulk insert".
It seems, however, that this is more related to PLSQL - at least I have no Idea how to use that from the same context or in a similar way as shown in my example. I'm neither ORACLE expert nor administrator and usage of the database is only a side problem within my project. What would you recommend?
Many thanks,
Michael

SQL Server Stored Procedure via SOCI/ODBC in C++

I am using the SOCI library to programmatically interact with a SQL Server DB via ODBC. I am having trouble getting values via output parameters in stored procedures. Some code (modeled after SOCI documentation)...
/*
* create procedure
* Dan.soci_proc #id int, #name varchar(32) output
* as begin
* set nocount on;
* select #name = name from Dan.soci_test where id = #id
* end
*/
std::string sql = "Dan.soci_proc :id, :name";
std::string name;
int proc_ndx = 1;
soci::procedure proc = (my_soci.get_session().prepare << sql, soci::use(proc_ndx),
soci::use(name));
std::cout << "\nAttempting to execute stored procedure " << size << " times."
<< std::endl;
for (; proc_ndx < adj_size; ++proc_ndx) {
try {
proc.execute();
while (proc.fetch())
std::cout << "Fetched: " << name << std::endl;
} catch (const soci::odbc_soci_error& e) {
std::cerr << "Error executing stored procedure." << std::endl;
std::cerr << e.what() << std::endl;
std::cerr << e.odbc_error_message() << std::endl;
return;
}
}
My code does not throw any errors or exceptions, but nothing is fetched, either. I have tried calling it many different ways (normal exec syntax, ODBC call syntax, etc.), but nothing seems to work. I'm wondering if the error goes back to this from here...
If an input/output parameter is omitted, or if a literal is supplied
for the parameter, the driver discards the output value.
Unfortunately, SOCI doesn't really seem to support parameter markers, at least as far as I can tell.
I have made the code work by using this kind of syntax...
std::string sql = "declare #name varchar(32); "
"exec Dan.soci_proc :id, #name = #name output; select #name";
...
soci::procedure proc = (my_soci.get_session().prepare << sql, soci::use(proc_ndx),
soci::into(name));
But that isn't ideal, for reasons that I think are obvious.
Has anyone out there used SOCI and have some input into what I need to do differently to get this to work?
EDIT: I received the following response from the soci-users forum/mailing list...
I haven't used SOCI for a couple of years but I did successfully get
stored procedures to work with ODBC on SQL Server, end of 2011, soci
version 2 (I think).
I remember that to do it I had to use statement rather than procedure.
I had to amend the backend to call SQLMoreResults in a loop.
Output parameters I think were not supported in SOCI and I handled
them direct with ODBC over which I also had a C++ layer.
However, since I'm a recent college grad (just started my first job this month!) and relatively inexperienced with C++ and database applications, I would really appreciate as much help as people are able to offer! For instance, regarding the above response - the last two points are not exactly clear to me.
The problems is that I was using the SOCI ODBC, which apparently does not support stored procedures.
SOCI Existing Backends
SOCI ODBC Backend - Stored Procedures
In the months since I initially asked this question, I have implemented my own SOCI backend, for which stored procedures work perfectly!

Interop exception with VC++ and MySQL C++ Connector

I am helping a friend with his bachelor thesis project. It is a program that calculates bending moments for various materials. One of the extra requirements that the client desires is database functionality to store and retrieve various pieces of data being used in the program.
The program is a forms application written in managed C++. I jumped on board to help with writing the database functionality. I am using MySQL Server 5.5 and the MySQL Connector/C++ to bridge the program and the database. Everything has been going pretty well and all the functionality we need works just fine, but only in debug. As soon as we put the program into release mode there is undefined behavior occurring at runtime. Below is the function that is used to open a connection to the database:
try
{
m_driver = get_driver_instance();
m_conn = m_driver->connect(m_dbHost, m_dbUser, m_dbPwd);
m_conn->setSchema(m_dbSchema);
}
catch(sql::SQLException &e)
{
int a = e.getErrorCode();
MessageBoxA(NULL, e.what(), "DB Error", MB_OK);
}
The values passed into the connect function are all std::string. In debug mode the connection is made with no issues. In release mode an exception is caught after the connect function is called, and displays the message "Unknown MySQL Server Host '####' (0)" where the #### is always some garbage text. I also notice that in the output window another exception is being thrown, this one is the type System.Runtime.InteropServices.SEHException.
I have been doing some research and have seen numerous cases of this exception on many forums (and here on stack exchange) but no one seems to be having this issue with the MySQL connector. My assumption is that the memory is being corrupted because the program is mixed mode, with the main program code being written in Managed C++ and my database helper code being in native C++ (as required by the connector).
Is there something I can change in my code to try and fix this issue to that the strings aren't being corrupted at run time. I have tried many different hacks to try and solve the problem but nothing has worked.
Thanks,
Tom
Update: I am now seeing this error in debug mode. I added code to retrieve values from the database and populate some text boxes on the form. The code is as follows:
// Populate the form with material details
String^ selectedMaterial = (String^)(comboBox1->SelectedItem);
string selectedMaterial_ = "";
MarshalString(selectedMaterial, selectedMaterial_);
sql::ResultSet* results = dbHelper.GetData("matname", selectedMaterial_);
if (results->rowsCount() == 1)
{
// Outdim
string outdim_ = "";
outdim_ = results->getString("outdim");
String^ outdim = gcnew String(outdim_.c_str());
textBox1->Text = outdim;
}
else
{
// !!!! Duplicate materials in list
}
When it tries to read outdim from the result set the SEHException is thrown, and the only other piece of information given is that it was thrown in an external component.
Update 2: I ran Application Verifier against the debug executable and then launched the program from VS2010. However the form window never loads so somewhere along the line the program must be getting halted. Strangely there is absolutely no information in the log files in Application Verifier. I also tried with the release version and I didnt get any useful information from that either.