Passing A Variable To SQL - c++

I have a variable that is an IP address. It is saved as text in my Access 2010 database. I am trying to run this query with ipSrc and the query always fails. My guess is that its seeing ipSrc as ipSrc and not as the actual IP address. I tried it with 'ipSrc' and just plain ipSrc and both reurn fail. Also tried ""ipSrc"", failed as well. This failed to. '&ipSrc'. Here is the statement.
SQLCHAR* query = (SQLCHAR*)"SELECT tblIP.[IPAddress], tblIP.[IPType], tblIP.[IPStatus], tblIP.[IPMax] FROM tblIP WHERE tblIP.[IPAddress]= ipSrc AND tblIP.[IPType]=3 AND tblIP.[IPStatus]=1 AND tblIP.[IPMax]=0;";
and here is the definition of ipSrc.
translate_ip(ip_header->source_ip, ipSrc);
Using printf it prints out as an actual IP address.
printf("\n Source IP: %s", ipSrc);

There's no way for the code to know, from what you have there, that ipSrc should be treated specially, it's just going to pass it through as-is.
You can probably try to construct the query string dynamically as a C++ string, and then use that to populate the query. Something like:
std::string strqry =
"SELECT tblIP.[IPAddress], "
+ " tblIP.[IPType], "
+ " tblIP.[IPStatus], "
+ " tblIP.[IPMax] "
+ "FROM tblIP "
+ "WHERE tblIP.[IPAddress] = '" + ipSrc + "' "
+ "AND tblIP.[IPType] = 3 "
+ "AND tblIP.[IPStatus] = 1 "
+ "AND tblIP.[IPMax] = 0"
+ ";";
SQLCHAR *query = (SQLCHAR *)(strqry.c_str());
// Now use query
And make sure you have control over the ipSrc value. Otherwise, you're subject to SQL injection attacks (in which case you'll want to use prepared/parameterised statements).

Related

how to show a variable in MESSAGE_TEXT in signal query in c++

I am using Signal query to catch errors in my c++ programming:
in the program user has to enter a database name and i check the database if it does not exists I have to return proper error message:
std::string database_name;
std::cin<<database_name;
if(!exists(database_name)){
query="SIGNAL SQLSTATE '42000' SET MYSQL_ERRNO='1049', MESSAGE_TEXT = 'Unknown database';";
}
how can I print the database_name variable after Unknown database?
You can format the string using
query = std::format( "... MESSAGE_TEXT = 'Unknown database {}'", database_name );
This will replace {} with the first string argument (database_name)
Or you could use a string stream like
std::ostringstream ss;
ss << "... MESSAGE_TEXT = 'Unknown database '" << database_name << "'";
query = ss.str();

Qt PL/SQL - Assignment Operator - Character String Buffer too small

I have been picking my brain for a while trying to figure this one out.
The problem I am having is that the function I am using in Oracle returns a BLOB. It's a list of items that are concatenated together using ||.
From the research I have done,
In the QSQLQuery docs it says "Stored procedures that uses the return statement to return values, or return multiple result sets, are not fully supported. For specific details see SQL Database Drivers." - which leads me to believe I may need to switch to a different codebase if Qt cannot handle it yet.
The documentation for the QOCI driver mentions this "Binary Large Objects (BLOBs) can be read and written, but be aware that this process may require a lot of memory. You should use a forward only query to select LOB fields (see QSqlQuery::setForwardOnly())."
I did set
query.setForwardOnly(true);
Before I prepared or executed the statement.
However, I still get this error
QSqlError("6502", "Unable to execute statement", "ORA-06502: PL/SQL: numeric or value error: character string buffer too small\nORA-06512: at line 55\n")
I had to scrub the code a bit, I hope this is still helpful to give context to what i'm trying to accomplish
temp_clob clob;
name varchar2(183) := ?;
start varchar2(16) := ?;
end varchar2(16) := ?;
count integer := ?;
return_val named_redacted_table_object; -- Sorry had to remove this, it's a table with more Date, Varchar, etc
begin
dbms_lob.createtemporary(temp_clob, true);
return_val := package_name.function_name (
set_name => name,
start_time => to_date(start, 'yyyy-mm-dd hh24:mi'),
end_time => to_date(end, 'yyyy-mm-dd hh24:mi'),
max_count => count);
-- In here was a loop that would break apart the removed table object and make it into strings along the following lines
-- '' || return_val(i).name || return_val(i).value || etc
-- and would store these into the CLOB / temp_clob
? := temp_clob;
end;
I could not get something as simple as this to work
begin
? := 'test123';
end;
With the assumption I could at least read this string in Qt.
Here is my code for Qt
QString name = "test";
QSqlQuery query(db);
query.setForwardOnly(true);
query.prepare(sql);
QString test_sql_text = ui->comboBox_test_text->currentText();
qDebug() << name;
query.bindValue(0, name);
query.bindValue(1, "2003-03-14 00:00");
query.bindValue(2, "2005-03-14 23:00");
query.bindValue(3, 2);
query.bindValue(4, QString(""), QSql::Out);
bool query_executed_ok = query.exec();
qDebug() << "did it execute?" << query_executed_ok;
// qDebug() << query.executedQuery();
qDebug() << query.boundValues();
qDebug() << query.lastError();
QSqlRecord rec = query.record();
qDebug() << rec;
int record_count = rec.count();
qDebug() << "Records: " << record_count;
while (query.next()) {
for(int i=0;i<record_count;i++) {
qDebug() << query.isValid() << " - " << rec.fieldName(i) << " " << query.value(i).toString();
}
}
The error posted appears to be from within the Oracle code; ORA.... You have stripped so much it's hard to see what is actually happening, especially the are where the error apparently occurred. But perhaps using Oracle supplied code that is specifically designed to handle CLOBs. Instead of
'' || return_val(i).name ...
Try
dbms_lob.append(temp_clob, to_clob(return_val(i).name))
begin
? := 'test123';
end;
Bind variables are used to assign values to variables. You define your variable in your pl/sql code and assign a value to it at runtime by using a bind variable. In that case pl/sql code will compile correctly.
In your code the bind variable is used to replace the pl/sql variable, not the value, which will fail. Your pl/sql block cannot be compiled because it cannot resolve the "?".
A valid use of bind variables would be
BEGIN
l_xyz := ?;
END;
where you assign the value test123 at runtime.
It took some fiddling, and I realize I gave fairly cryptic code. So thank you to belayer and Koen for taking a shot at my mess.
What I was able to determine and get working for anyone else running into this:
Let me start off by saying I am not sure if this is a bug, or if i'm doing something in a way that was not intended by the designers of QSqlQuery (The class for handling SQL calls).
The call would work in SQL developer and I would see the intended CLOB with all characters. I was unable to get DBMS_Output to work, however, I saw this post saying to reserve space on the string before binding it to the query.
It solves my issue and shows the result in the debug window. However, it presents a new problem. What if the string becomes larger than my hard coded reserve value?
Here's the updated code for that
query.prepare(sql);
QString name= ui->comboBox_name->currentText();
qDebug() << project;
query.bindValue(":name", project);
query.bindValue(":start_date", "2005-03-14 00:00");
query.bindValue(":end_date", "2006-03-14 23:00");
query.bindValue(":max_count", 3);
QString testStr ="*****";
//testStr.truncate(0); //Maybe this works too?
testStr.reserve( 1000000 ); // This did it for sure
qDebug() << testStr.capacity();
query.bindValue(":result_clob", testStr, QSql::Out);
bool query_executed_ok = query.exec();
qDebug() << "did it execute?" << query_executed_ok;
if (query_executed_ok) {
testStr = query.boundValue(":result_clob").toString();
qDebug() << testStr;
} else {
qDebug() << "string is empty";
}
I got the idea to do this, from THIS post.

insert multiple char * into a const char* with pre filled text

i have setup a working mysql connector for my c++ project. Now i'm making a login for registered users.
i want to get the username and password into the SQLquery string.
i am trying to get this working:
currently its displaying noting and the game crashes.
#include "boost/lexical_cast.hpp" //boost
#include <cgl\cgl.h> // game library (core media library)
#include <sstream> // sstream
char* username=DEFSER;
char* password=PASS12345;
const char *SQLquery;
std::string SQLquery("SELECT * FROM Users WHERE UserName='" + boost::lexical_cast<std::string>(username) + "' AND PassWord='" + boost::lexical_cast<std::string>(password) + "'");
what i want to get out of SQLquery:
SELECT * FROM Users WHERE UserName='DEFSER' AND PassWord='PASS12345'
and i execute it in this way:
res = stmt->executeQuery(SQLquery);
this is not a fully working code i only want to know how i can get the username and password into the SQLquery.
error when i try to run the query:
Run-Time Check Failure #3 - The variable 'SQLquery' is being used without being initialized.
What you are doing is not concatenating strings, you are adding std::string objects to a literal string pointer.
The std::string class handles concatenation of C-style strings just fine without any lexical_cast, so just do e.g.
std::string SQLquery = "SELECT * FROM Users WHERE UserName='" +
username + "' AND PassWord='" + password + "'";
After testing the above solution doesn't actually work for me. But the following does:
std::string SQLQuery = (std::ostringstream() << "SELECT * FROM Users WHERE UserName='"
<< username << "' AND PassWord='" << password << "'").str();

PQexecParams in C++, query error

I'm using pqlib with postgresql version 9.1.11
I have the following code
const char *spid = std::to_string(pid).c_str();
PGresult *res;
const char *paramValues[2] = {u->getID().c_str(), spid};
std::string table;
table = table.append("public.\"").append(Constants::USER_PATTERNS_TABLE).append("\"");
std::string param_name_pid = Constants::RELATION_TABLE_PATTERN_ID;
std::string param_name_uid = Constants::RELATION_TABLE_USER_ID;
std::string command = Constants::INSERT_COMMAND + table + " (" + param_name_uid + ", " + param_name_pid + ") VALUES ($1, $2::int)";
std::cout << "command: " << command << std::endl;
res = PQexecParams(conn, command.c_str(), 2, NULL, paramValues, NULL, NULL,0);
Where
INSERT_COMMAND = "INSERT INTO " (string)
USER_PATTERN_TABLE = "User_Patterns" (string)
RELATION_TABLE_PATTERN_ID = "pattern_id" (string)
RELATION_TABLE_USER_ID = "user_id" (string)
pid = an int
u->getID() = a string
conn = the connection to the db
The table "User_Patterns" is defined as
CREATE TABLE "User_Patterns"(
user_id TEXT references public."User" (id) ON UPDATE CASCADE ON DELETE CASCADE
,pattern_id BIGSERIAL references public."Pattern" (id) ON UPDATE CASCADE
,CONSTRAINT user_patterns_pkey PRIMARY KEY (user_id,pattern_id) -- explicit pk
)WITH (
OIDS=FALSE
);
I already have a user and a pattern loaded into their respective tables.
The command generated is :
INSERT INTO public."User_Patterns" (user_id, pattern_id) VALUES ($1, $2::int)
I also tried with $2, $2::bigint, $2::int4
The problem is:
I receive the error :
ERROR: invalid input syntax for integer: "public.""
I already use PQexecParams to store users and patterns, the only difference is that they all have text/xml fields (the only int field on patterns is a serial one and I don't store that value myself) but because the user_patterns is a relation table I need to store and int for the pattern_id.
I already read the docs for pqlib and saw the examples, both are useless.
The problem is in the lines:
const char *spid = std::to_string(pid).c_str();
const char *paramValues[2] = {u->getID().c_str(), spid};
std::to_string(pid) creates temporary string and .c_str() returns a pointer to an internal representation of this string, which is destroyed at the end of the line, resulting in a dead pointer. You may also see answer to the question
stringstream::str copy lifetime

How to use transactions in Informix CSDK and OIC++

I'd need some advice how to handle transactions with Informix CSDK and OIC++.
conn is a open connection object. Select works find. The database here is setup with logging — as I found out while update stmt on its own does nothing.
Here's what I tried:
conn.SetTransaction( ITConnection::BEGIN );
qtext = "UPDATE transit_kunde_s SET erledigt='Y' WHERE transitkunde='"+ts+"'";
cout << qtext << endl;
code = query_up.ExecForStatus(qtext.c_str());
cout << "code " << code << endl;
conn.SetTransaction( ITConnection::COMMIT );
okay once again I answer myself...
from Informix C++ DocNotes
Operations can now be performed on large objects within a fetched row even though the connection is still checked out (locked). A connection is checked out after the ITQuery::ExecForIteration() method returns multiple rows in the result set. It remains checked out until either the last row in the result set has been fetched with ITQuery::NextRow() or the query processing has been terminated by calling ITQuery::Finish(). While a connection is checked out, no other query can be executed on that connection.
So as I am in the while loop of one query result iteration I need for another update query a new connection
// already have 2 connection objects: conn, conn2
ITQuery query(conn);
ITQuery query_up(conn2);
string qtext;
qtext = "SELECT * FROM transit_kunde_s WHERE erledigt='N' ORDER BY transitkunde";
okay = query.ExecForIteration(qtext.c_str());
while (row = query.NextRow()) {
// do stuff
// NOW WANT TO DO ANOTHER QUERY? --> NEED ANOTHER CONNECTION!!
ok_ta = conn2.SetTransaction( ITConnection::BEGIN);
qtext = "UPDATE transit_kunde_s SET erledigt='Y' WHERE transitkunde='"+ts+"'";
code = query_up.ExecForStatus(qtext.c_str());
ok_ta = conn2.SetTransaction( ITConnection::COMMIT );
}
// we see later the 1st query to be finished here
query.Finish();