PQexecParams in C++, query error - c++

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

Related

Does QT have reflections for C++?

I want to create a SQL table in QT C++. So I have made this code.
And it is going to create a database for me, where the first argument tableName is the name of the table I want to create. Then the next argument is quite tricky.
Here, columns, specify the column name and it's data type. I think this is a bad way to do. Example
QVector<QPair<QString, QString>> myColumns = new QVector<QPair<QString, QString>>{{"ID", "BIGINT"}, {"logging_id", "INT"}};
Because If i have for example like 50 columns. The myColumns is going to be very long.
My question if QT C++ have some kind of reflections, so I can:
Get the name if every field
Get the data type of every field
If the field is an array, then I'm going to know how many elements there are inside that array
I was planning to have an entity class where I create a class, and use that class to get the information to create each columns in the database.
void Database::createTable(QString tableName, const QVector<QPair<QString, QString>> columns){
QSqlQuery query;
for (int i = 0; i < columns.length(); i++){
/* Get the Qpair values */
QString columnName = columns.at(i).first;
QString dataType = columns.at(i).second;
/* If key is ID, then try to create a new table */
if(columnName == "ID"){
query.exec("CREATE TABLE " + tableName + "(" + columnName + " " + dataType + " NOT NULL AUTO_INCREMENT PRIMARY KEY)");
continue;
}
/* If not, then try append new columns */
query.exec("ALTER TABLE " + tableName + " ADD " + columnName + " " + dataType);
}
}

ORA-00947: not enough values when creating object in Oracle

I created a new TYPE in Oracle in order to have parity between my table and a local c++ object (I am using OCCI interface for C++).
In the code I use
void insertRowInTable ()
{
string sqlStmt = "INSERT INTO MY_TABLE_T VALUES (:x)";
try{
stmt = con->createStatement (sqlStmt);
ObjectDefinition *o = new ObjectDefinition ();
o->setA(0);
o->setB(1);
o->setC(2);
stmt->setObject (1, o);
stmt->executeUpdate ();
cout << "Insert - Success" << endl;
delete (o);
}catch(SQLException ex)
{
//exception code
}
The code compiles, connects to db but throws the following exception
Exception thrown for insertRow Error number: 947 ORA-00947: not enough
values
Do I have a problematic "sqlStmt"? Is something wrong with the syntax or the binding?
Of course I have already setup an environment and connection
env = Environment::createEnvironment (Environment::OBJECT);
occiobjm (env);
con = env->createConnection (user, passwd, db);
How many columns are in the table? The error message indicates that you didn't provide enough values in the insert statement. If you only provide a VALUES clause, all columns in the table must be provided. Otherwise you need to list each of the columns you're providing values for:
string sqlStmt = "INSERT INTO MY_TABLE_T (x_col) VALUES (:x)";
Edit:
The VALUES clause is listing placeholder arguments. I think you need to list one for each value passed, e.g.:
string sqlStmt = "INSERT INTO MY_TABLE_T (GAME_ID, VERSION) VALUES (:x1,:x2)"
Have a look at occidml.cpp in the Oracle OCCI docs for an example.

Cassandra cppdriver Query String Buffer Overflow?

I have been writing a wrapper for the Cassandra cppdriver for CQL3.0 and I have come across some odd behavior, and I am not sure if it is typical or a bug.
For reference, I am working with with the cppdriver code release on 4 September (from the repository), libuv0.10 and off of the songs / playlist example posted on the datastax website (http://www.datastax.com/documentation/cql/3.1/cql/ddl/ddl_music_service_c.html)
The problem that I am having is with executing query strings. There seems to be some threshold of characters after which the query string being sent to Cassandra becomes garbage. The code that I am using to construct and send the string to the cppdriver library (and parse the results) is provided below. I added a function (cass_session_print_query) to the cassandra.h and session.cpp files to print out generated statement.
map<string, vector<string> > retresults;
int i = 0, ccount;
stringstream ss;
vector<string> keys = get.GetList();
vector<string>::iterator kit = keys.begin();
map<int, pair<string, string> > primkeys = get.GetMap();
map<int, pair<string, string> >::iterator mit = primkeys.begin();
if (!keys.empty())
{
ss << "SELECT " << (*kit);
++kit;
for ( ; kit != keys.end(); ++kit)
ss << "," << (*kit);
ss << " FROM " << tablename;
if (!primkeys.empty())
{
ss << " WHERE ";
ss << mit->second.first << " = ?";
++mit;
for ( ; mit != primkeys.end(); ++mit)
ss << " and " << mit->second.first << " = ?";
mit = primkeys.begin();
}
ss << ";";
cass_bool_t has_more_pages = cass_false;
const CassResult* result = NULL;
CassString query = cass_string_init(ss.str().c_str());
CassStatement* statement = cass_statement_new(query, primkeys.size());
for ( ; mit != primkeys.end(); ++mit)
cass_statement_bind_string(statement, i++, cass_string_init(mit->second.second.c_str()));
cass_statement_set_paging_size(statement, 100);
do
{
cass_session_print_query(statement);
CassIterator* iterator;
CassFuture* future = cass_session_execute(session_, statement);
if (cass_future_error_code(future) != 0)
{
CassString message = cass_future_error_message(future);
fprintf(stderr, "Error: %.*s\n", (int)message.length, message.data);
break;
}
result = cass_future_get_result(future);
ccount = cass_result_column_count(result);
vector<string> cnames;
for (i = 0; i < ccount; i++)
cnames.push_back(cass_result_column_name(result, i).data);
iterator = cass_iterator_from_result(result);
ListVector::iterator vit;
while (cass_iterator_next(iterator))
{
const CassRow* row = cass_iterator_get_row(iterator);
for (vit = cnames.begin(); vit != cnames.end(); ++vit)
{
CassString value;
char value_buffer[256];
cass_value_get_string(cass_row_get_column_by_name(row, (*vit).c_str()), &value);
if (value.length == 0 || value.data == NULL)
continue;
memcpy(value_buffer, value.data, value.length);
value_buffer[value.length] = '\0';
retresults[(*vit)].push_back(value_buffer);
}
}
has_more_pages = cass_result_has_more_pages(result);
if (has_more_pages)
cass_statement_set_paging_state(statement, result);
cass_iterator_free(iterator);
cass_result_free(result);
} while (has_more_pages);
}
return retresults;
With this, an initial query string of SELECT id,album,title,artist,data FROM songs; results in a Cassandra query string of SELECT id,album,title,artist,data FROM songs;. However, if I add one more column to the SELECT portion SELECT id,album,title,artist,data,tags FROM songs; the query string in the Cassandra cppdriver library becomes something like: ,ar����,dat�� jOM songX. This results in the following error from Cassandra / library: Error: line 1:49 no viable alternative at character '�'.
I have also tried fewer columns, but with a WHERE clause, and that results in the same problem.
Is this a bug? Or am I building and sending strings to the cppdriver library incorrectly?
You should cass_future_wait() on the execute future before testing the error code.
Unrelated: there are also a couple of things that should be freed (future, statement), but I'm assuming that was omitted to keep this concise.
So, it looks like (for whatever reason) I HAVE to parse out the row key from the results. I checked the example, and I was able to not parse out the row key information and everything still worked. I am not yet entirely sure what is forcing me to do this (compared to the provided paging example), but for others, you need to include the following within the while (cass_iterator_nex(iterator)) block to "magically" fix my code above.
CassUuid key;
char key_buffer[CASS_UUID_STRING_LENGTH];
const CassRow* row = cass_iterator_get_row(iterator);
cass_value_get_uuid(cass_row_get_column(row, 0), key);
cass_uuid_string(key, key_buffer);
This is really a long shot, but since you mentioned the Music Service example, did you possibly download and use cql_collections.zip query strings? If so, the strings (now fixed) had minor syntax errors:
-use music
-CREATE TABLE music.songs ( id uuid PRIMARY KEY, album text, artist text, data blob, reviews list, tags set, title text, venue map
+use music;
+CREATE TABLE music.songs ( id uuid PRIMARY KEY, album text, artist text, data blob, reviews list, tags set, title text, venue map);
AeroBuffalo's code worked for me except that I had to put '&' in front of the second parameter of cass_value_get_uuid() function. It required reference type.
cass_value_get_uuid(cass_row_get_column(row, 0), &key);

CreateQuery constructor with getting parameter list

I'm new here and this is my second question, but as the first, I have a problem already tried to solve in different ways, but have not found a solution, so I'm resorting to you, here we go.
My code:
string sql = "SELECT NEW Filial(fil.NumSequencial, fil.Numero, fil.Nome, fil.Cnpj, fil.Empresa, fil.LstUsuario)" +
" FROM Filial fil" +
" join fetch fil.LstUsuario usrFil";
IQuery query = session.CreateQuery(sql);
lstFilial = (List<Filial>)query.List<Filial>();
I've tried with and without the line "join fetch", but the error is always the same:
{"illegal syntax near collection: id [SELECT NEW Filial(fil.NumSequencial, fil.Numero, fil.Nome, fil.Cnpj, fil.Empresa, fil.LstUsuario) FROM Leitor_NFe_XML_Entidade.Filial fil\tjoin fetch fil.LstUsuario usrFil]"}
The constructor:
public Filial(long numSequencial, int numero, string nome, string cnpj, Empresa empresa, IList<Usuario> lstUsuario)
{
this.numSequencial = numSequencial;
this.numero = numero;
this.nome = nome;
this.cnpj = cnpj;
this.empresa = empresa;
this.lstUsuario = lstUsuario;
}
Am thankful since already

C++ Mysql Real Escape String Issue

Hmm, for some reason, its only doing this on the first username (and password) and does it for how big my my vector is. Any ideas on why?
int eMysql::strip(string &input) {
char* from = new char[strlen(input.c_str()) * 3 + 1];
mysql_real_escape_string(&mysql, from, input.c_str(), input.length());
input = input.assign(from);
delete from;
}
Where its used:
if(query.size() > 0) {
mysql->strip(query[0]);
mysql->strip(query[1]);
mysql->query("SELECT `username` FROM `users` where `username` = '"+ query[0] +"';");
I suggest building the query as a separate string variable rather than passing the mess in the argument:
static const char fixed_text[] = "SELECT `username` FROM `users` where `username` = '";
std::string query_text(fixed_text);
query_text += query[0];
query_text += "';";
mysql->query(query_text);
This technique allows you to examine the query before it is sent to MySql.
I suggest you examine the query[0] variable for any strange characters such as \r and \n. The MySql manual has a section listing characters that need to be escaped.