MySQL connector PreparedStatement->setString not working C++ - c++

So, basically all this code does is search the database for a user with a certain username and password, and returns a nullptr if it doesn't find one.
Gebruiker* Gebruiker_DAO::getGebruiker(string login, string wachtwoord)
{
PreparedStatement *prep_stmt = nullptr;
ResultSet *res = nullptr;
Gebruiker* gebruiker = nullptr;
int rowcount = 0;
try {
prep_stmt = dbConn->getConnection()->prepareStatement("SELECT * FROM Gebruiker WHERE Gebruiker_login = ? AND Gebruiker_wachtwoord = ?");
prep_stmt->setString(1, login);
prep_stmt->setString(2, wachtwoord);
res = prep_stmt->executeQuery();
while (res->next()) {
gebruiker = new Gebruiker(login, res->getBoolean("Gebruiker_isAdmin"), res->getString("Bedrijf"),res->getBoolean("Gebruiker_isActief"),res->getInt("Werknemer_ID"));
}
}
catch(SQLException& e) {
console.log(e.what(), console.Error);
return nullptr;
}
return gebruiker;
}
The issue is that setString throws an "std::bad_alloc at memory location ..."
Ive noticed before that trying to put a string in an SQLString also throws an error. Until now ive used a workaround by putting stuff in SQLStrings.
SQLString schema = "groep003B";
dbConn->getInstance()->setSchema(schema);
dbConn->getInstance()->connect();
For some weird reason this DOES work...
Is there something i am doing wrong? I have seen examples where people use strings, but for some reason this does not work for me... Every time i try to put a variable std::string in an SQLString it gives a memory issue.

Related

Creating Internal Accounts in SAS Metadata Server by programm on SAS Base

I'm trying to create Internal Accounts programmaticaly by using proc metadata.
The code section below creates person with External Login.
put"<Person Name=%str(%')&&PersonName&i.%str(%')>";
put"<Logins>";
put"<Login Name=%str(%')Login.&&PersonName&i.%str(%') Password=%str(%')&&word&i.%str(%')/>";
put"</Logins>";
put"</Person>";
To create ExternalLogin we can set attribute Password, and in SAS Metadata it will be encrypted automaticaly.
But to create InternalLogin type of object it is necessary to make the hash value of the password and the salt. I know that the standard sas002 encryption method, but in the case of using proc pwencode how to obtain the value of salt?
Is it possible create InternalLogin by using SAS Base?
Thanx.
So on. I found an article that can tell us how to create Stored Process for this problem. My answer is addition to the article.
The approach is base on execute java methods from sas programm.
1. Prerare setPasswd.java class
I've modified class from article. Separate code to connect to metadata server and create InternalLogin
import java.rmi.RemoteException;
import com.sas.metadata.remote.AssociationList;
import com.sas.metadata.remote.CMetadata;
import com.sas.metadata.remote.Person;
import com.sas.metadata.remote.MdException;
import com.sas.metadata.remote.MdFactory;
import com.sas.metadata.remote.MdFactoryImpl;
import com.sas.metadata.remote.MdOMIUtil;
import com.sas.metadata.remote.MdOMRConnection;
import com.sas.metadata.remote.MdObjectStore;
import com.sas.metadata.remote.MetadataObjects;
import com.sas.metadata.remote.PrimaryType;
import com.sas.metadata.remote.Tree;
import com.sas.meta.SASOMI.ISecurity_1_1;
import com.sas.iom.SASIOMDefs.VariableArray2dOfStringHolder;
public class setPasswd {
String serverName = null;
String serverPort = null;
String serverUser = null;
String serverPass = null;
MdOMRConnection connection = null;
MdFactoryImpl _factory = null;
ISecurity_1_1 iSecurity = null;
MdObjectStore objectStore = null;
Person person = null;
public int connectToMetadata(String name, String port, String user, String pass){
try {
serverName = name;
serverPort = port;
serverUser = user;
serverPass = pass;
_factory = new MdFactoryImpl(false);
connection = _factory.getConnection();
connection.makeOMRConnection(serverName, serverPort, serverUser, serverPass);
iSecurity = connection.MakeISecurityConnection();
return 0;
}catch(Exception e){
return 1;
}
}
public setPasswd(){};
public int changePasswd(String IdentityName, String IdentityPassword) {
try
{
//
// This block obtains the person metadata ID that is needed to change the password
//
// Defines the GetIdentityInfo 'ReturnUnrestrictedSource' option.
final String[][] options ={{"ReturnUnrestrictedSource",""}};
// Defines a stringholder for the info output parameter.
VariableArray2dOfStringHolder info = new VariableArray2dOfStringHolder();
// Issues the GetInfo method for the provided iSecurity connection user.
iSecurity.GetInfo("GetIdentityInfo","Person:"+IdentityName, options, info);
String[][] returnArray = info.value;
String personMetaID = new String();
for (int i=0; i< returnArray.length; i++ )
{
System.out.println(returnArray[i][0] + "=" + returnArray[i][1]);
if (returnArray[i][0].compareTo("IdentityObjectID") == 0) {
personMetaID = returnArray[i][1];
}
}
objectStore = _factory.createObjectStore();
person = (Person) _factory.createComplexMetadataObject(objectStore, IdentityName, MetadataObjects.PERSON, personMetaID);
iSecurity.SetInternalPassword(IdentityName, IdentityPassword);
person.updateMetadataAll();
System.out.println("Password has been changed.");
return 0; // success
}
catch (MdException e)
{
Throwable t = e.getCause();
if (t != null)
{
String ErrorType = e.getSASMessageSeverity();
String ErrorMsg = e.getSASMessage();
if (ErrorType == null)
{
// If there is no SAS server message, write a Java/CORBA message.
}
else
{
// If there is a message from the server:
System.out.println(ErrorType + ": " + ErrorMsg);
}
if (t instanceof org.omg.CORBA.COMM_FAILURE)
{
// If there is an invalid port number or host name:
System.out.println(e.getLocalizedMessage());
}
else if (t instanceof org.omg.CORBA.NO_PERMISSION)
{
// If there is an invalid user ID or password:
System.out.println(e.getLocalizedMessage());
}
}
else
{
// If we cannot find a nested exception, get message and print.
System.out.println(e.getLocalizedMessage());
}
// If there is an error, print the entire stack trace.
e.printStackTrace();
}
catch (RemoteException e)
{
// Unknown exception.
e.printStackTrace();
}
catch (Exception e)
{
// Unknown exception.
e.printStackTrace();
}
System.out.println("Failure: Password has NOT been changed.");
return 1; // failure
}
}
2. Resolve depends
Pay attention to imports in class. To enable execute the code below necessary set CLASSPATH enironment variable.
On linux you can add the next command in %SASConfig%/Lev1/level_env_usermods.sh:
export CLASSPATH=$CLASSPATH:%pathToJar%
On Windows you can add/change environment variable by Advanced system settings
So where should you search jar files? They are in folder:
%SASHome%/SASVersionedJarRepository/eclipse/plugins/
Which files i should include in path?
I've include all that used in OMI(Open Metadata Interface).Also I've added log4j.jar (not working without this jar. Your promts will be helpful):
sas.oma.joma.jar
sas.oma.joma.rmt.jar
sas.oma.omi.jar
sas.svc.connection.jar
sas.core.jar
sas.entities.jar
sas.security.sspi.jar
log4j.jar
setPasswd.jar (YOUR JAR FROM THE NEXT STEP!)
Choose files from nearest release. Example:
Here I'm set file from v940m3f (fix release).
Other ways is here.
3. Compile setPasswd.jar
I'm tried use internal javac.exe into SAS, but it's not worked properly. So ou need to download JDK to compile jars. I've create Bat-file:
"C:\Program Files\Java\jdk1.8.0_121\bin\javac.exe" -source 1.7 -target 1.7 setPasswd.java
"C:\Program Files\Java\jdk1.8.0_121\bin\jar" -cf setPasswd.jar setPasswd.class
Paramethers -source and -target will helpful if your version of JDK is upper, that usses in SAS. Version of "sas"-java you can see by:
PROC javainfo all;
run;
Search the next string in log:
java.vm.specification.version = 1.7
4. Finally. SAS Base call
Now we can call Java code by this method (All methods available here):
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "%SERVER%", "%PORT%", "%ADMIN%", "%{SAS002}HASHPASSORPASS%", rc1);
j.callIntMethod("changePasswd", "testPassLogin", "pass1", rc2);
j.delete();
run;
In log:
UserClass=Normal
AuthenticatedUserid=Unknown
IdentityName=testPass
IdentityType=Person
IdentityObjectID=A56RQPC2.AP00000I
Password has been changed.
Now time to test. Create new user with no passwords.
Execute code:
data test;
dcl javaobj j ("setPasswd");
j.callIntMethod("connectToMetadata", "&server.", "&port.", "&adm", "&pass", rc1);
j.callIntMethod("changePasswd", "TestUserForStack", "Overflow", rc2);
j.delete();
run;
Now our user has InternalLogin object.
Thanx.

QMYSQL query failing

I'm currently working on my project within C++ using Qt. I have MySQL as database storage and the idea is to make a small messenger like MSN and Skype.
However, my MySQL queries are failing. It simply gets no results or gives me an error. There's loads of code coming up, I'm sorry for that.
This is my mysql.cpp which creates and opens the database connection:
#include "mysql.h"
mysql::mysql()
{
this->db = QSqlDatabase::addDatabase("QMYSQL", "QMYSQL");
this->db.setHostName("localhost");
this->db.setUserName("root");
this->db.setPassword("Eequi4");
this->db.setDatabaseName("test");
this->db.open();
}
mysql::~mysql()
{
}
mysql_result mysql::create_result(QString query)
{
return mysql_result(this->db.exec(query));
}
QSqlError mysql::error()
{
return this->db.lastError();
}
The connection is opened. That works correctly.
This is my mysql_result.cpp, the file I use to add parameters, insert, get results etc:
#include "mysql_result.h"
mysql_result::mysql_result(QSqlQuery query)
{
this->query = query;
}
void mysql_result::add_parameter(QVariant value)
{
this->query.addBindValue(value);
}
void mysql_result::add_parameter(QString key, QVariant value)
{
this->query.bindValue(key, value);
}
int mysql_result::get_last_id()
{
return this->query.lastInsertId().toInt();
}
void mysql_result::execute()
{
this->query.execBatch();
}
QSqlQuery mysql_result::get_query()
{
return this->query;
}
mysql_result::~mysql_result()
{
}
Okay, this should work. If I have the following code, it correctly returns all member first_name's from the database:
mysql_result res = _mysql->create_result("SELECT * FROM members");
QSqlQuery qry = res.get_query();
while (qry.next())
{
qDebug() << qry.value("first_name");
}
In member_controller.cpp (the class I use to retrieve members by name/id), I got this:
member* member_controller::get_member(int id)
{
mysql_result result = engine::get_mysql().create_result("SELECT * FROM members WHERE member_id = :ID");
result.add_parameter(":ID", id);
QSqlQuery query = result.get_query();
if (query.exec() && query.next())
{
return new member(id, query.value("first_name").toString(), query.value("second_name").toString(), query.value("screen_name").toString(), query.value("email").toString(), query.value("status").toString());
}
else
{
qDebug() << engine::get_mysql().error() << "\n";
qDebug() << query.lastError() << "\n";
}
return new member(0, "", "", "", "", "");
}
What it does it will go to the else, and I get the error invalid syntax near :ID. If I replace :ID with #ID (just like in C#), it will go to the else without error code.. I don't know what the problem is.
Two things. The code needs to be optimized a bit and made easier, I'm gonna work on that. Also, is it possible/allowed to put code in a pastebin and paste the URL rather than put the code here?
Try changing your query to this:
"SELECT * FROM members WHERE member_id = ?"
and add your param like this:
result.add_parameter(0, id);
I'd also suspect, if (query.exec() && query.next()) is incorrect, and the check for .next() should be removed as I'd imagine that requires another record to exist in the result set.

Connect and query database in Managed C++ using SqlConnection

I'm building a project in C++ in Visual Studio 2012 and I've started by writing some classes for database access. Using SQL Server data tools I've managed to create a SQL project in my solution.
Now, my question is: How can I use the types in System::Data::SqlClient namespace to connect to the database in my code? All the examples I get are using the database as reference.
Thanks in advance
If my answer helps someone, I have used the classes SqlDataReader and SqlCommand in order to select some data from db. Note that I'm fetching the ConnectionString from an App.Config I've created earlier (how it could be done).
SqlDataReader getSqlDataReader(String ^_sql)
{
SqlDataReader ^_sqlDataReader = nullptr;
SqlConnection ^_connection = gcnew SqlConnection();
ConnectionStringSettings ^connectionSettings = ConfigurationManager::ConnectionStrings["AppDefaultConnection"];
this->_connection->ConnectionString = connectionSettings->ConnectionString;
try {
this->_connection->Open();
}
catch (Exception ^_exception)
{
Console::WriteLine("Error : " + _exception->Message);
return nullptr;
}
try
{
SqlCommand ^_sqlCommand = gcnew SqlCommand(_sql,_connection);
_sqlDataReader = _sqlCommand->ExecuteReader();
}
catch(Exception ^_exception)
{
Console::WriteLine("Error : " + _exception->Message);
return nullptr;
}
return _sqlDataReader;
}
To proper build the SQL we should be aware of the class SqlParameter (example for C#) and avoid SQL injection attacks.
To use the getSqlDataReader function:
SqlDataReader ^reader = getSqlDataReader(yourParameterizedQueryString);
List<TypeToFetch>^ data = gcnew List<TypeToFetch^>();
if(reader != nullptr && reader->HasRows)
{
TypeToFetch^ typeToFetch = gcnew TypeToFetch();
while(reader->Read())
{
// example
TypeToFetch->id = (int) reader["Id"];
TypeToFetch->name = reader["Name"]->ToString();
data->Add(typeToFetch);
}
}
This question/answer can help on INSERT.

SQLite UPDATE fails to overwrite existing value

I have the following problem that has me stumped. As a note to keep in mind, I am using a precompiled sqlite3.dll rather than Qt's built-in SQLite support.
Table creation code:
CREATE TABLE STUDY(
Name NOT NULL,
UserName NOT NULL REFERENCES USERS(UserName),
Description DEFAULT NULL,
PathToOsirixDB DEFAULT NULL,
PRIMARY KEY(Name, UserName)
)
The following C++ code fails to update the value in column PathToOsirixDB if it already contains a value.
It fails silently, with no error returned. That would imply that no rows are matched in the UPDATE. However, if I take the same UPDATE with valid entries for user and study to match a row and run it via either the SQLite Manager Firefox plugin, or the command line tool, it works properly.
void CStudyDatabase::SetOsirixDBForStudy(const QString user, const QString study, const QString path)
{
if (mp_db)
{
int before = sqlite3_total_changes(mp_db);
QString insert = QString("UPDATE STUDY SET PathToOsirixDB = '%1' WHERE Name = '%2' AND UserName = '%3'").arg(path, study, user);
if (!InsertData(insert))
{
int after = sqlite3_total_changes(mp_db);
if (after - before >= 1)
{
SetOsirixDB(path.toAscii().data());
emit ReturnOsirixDB(osirix_db);
}
else
{
emit DatabaseError(QString("Failed to update the target path."));
}
}
}
}
And for Insert Data
int CStudyDatabase::InsertData(const QString insert)
{
char *err_msg = 0;
int rc = sqlite3_exec(mp_db,
insert.toStdString().c_str(),
NULL,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
return rc;
}
Any insights are appreciated. Thank you.
UPDATE: added the following code to SetOsiriXDBForStudy to see if we actually find a row to update:
osirix_db = QString("");
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
int rc = 0;
char *err_msg = 0;
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (!(QString(osirix_db).isEmpty()))
studyrowfound = true;
In this case, it leaves osirix_db as an empty string.
But, if I execute this function:
void CStudyDatabase::QueryOsirixDB(const QString user, const QString study)
{
int rc = 0;
char *err_msg = 0;
// we query the OrisixDB via the callback and then emit the signal if all went well
QString query = QString("SELECT PathToOsirixDB FROM STUDY WHERE Name = '%1' AND UserName = '%2'").arg(study, user);
rc = sqlite3_exec(mp_db,
query.toStdString().c_str(),
&OsirixDBCallback,
this,
&err_msg);
if (rc)
SignalDatabaseError(&err_msg);
if (QString(osirix_db).isEmpty())
emit NeedToSetOsirixDB(user, study, QString());
else
emit ReturnOsirixDB(osirix_db);
}
Then it does correctly retrieve the expected value into osirix_db.
Last update: found the problem. It was leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.
There were leading spaces on user and study. Had been staring at the same debugger statements for too long and glossed over the extra spaces. The failing SELECT was a big clue that there was something wrong in the construction of the SQL.

subsonic 3.0 active record update

I am able to retrieve database values and insert database values, but I can't figure out what the Update() syntax should be with a where statement.
Environment -> ASP.Net, C#
Settings.ttinclude
const string Namespace = "subsonic_db.Data";
const string ConnectionStringName = "subsonic_dbConnectionString";
//This is the name of your database and is used in naming
//the repository. By default we set it to the connection string name
const string DatabaseName = "subsonic_db";
Retreive example
var product = equipment.SingleOrDefault(x => x.id == 1);
Insert Example
equipment my_equipment = new equipment();
try
{
// insert
my_equipment.parent_id = 0;
my_equipment.primary_id = 0;
my_equipment.product_code = product_code.Text;
my_equipment.product_description = product_description.Text;
my_equipment.product_type_id = Convert.ToInt32(product_type_id.SelectedItem.Value);
my_equipment.created_date = DateTime.Now;
my_equipment.serial_number = serial_number.Text;
my_equipment.Save();
}
catch (Exception err)
{
lblError.Text = err.Message;
}
Edit: Think that I was just too tired last night, it is pretty easy to update. Just use the retrieve function and use the Update() on that.
var equip = Equipment.SingleOrDefault(x => x.id == 1);
lblGeneral.Text = equip.product_description;
equip.product_description = "Test";
equip.Update();
Resolved. View answer above.