In C++, how can I establish an SQL connection to store data in an SQL database?
You should have a look at C preprocessors that exists traditionaly with databases (ecpg for postgres, Pro*C for oracle ... which lets you embed straight SQL directly in your source files) or an orginal system for mysql. ECPG will do with C++, that is/was not the case for some other preprocessors ...
IF you are targetting Windows, then you might want to use ODBC.
you could try wxSqlite with SQLite as Database. This offers you an open source connection header / c++ file to get started.
In general - you should get some kind of library that offers you the required functionality. All major DB vendors should offer at least a C library. Most of the time you get a C++ library or wrapper for the C one.
Use SQLAPI++ - it's cross platform and supports MS SQL Server, Oracle, Postgres and others. Very easy to use.
http://www.sqlapi.com/
If you targeting windows you can always use the import ability.
#import "c:\Program Files\Common Files\System\ADO\msado15.dll" no_namespace rename( "EOF", "EndOfFile" )
Then you could make a wrapper to deal with the SQL.
Little example, just to open close a connection
// H
class CExtAdoDatabase
{
public:
CExtAdoDatabase( const char* p_cConnectString="", const char* p_cUsername="", const char* p_cPwd="" );
virtual ~CExtAdoDatabase();
bool Open( const char* p_cConnectString="", const char* p_cUsername="", const char* p_cPwd="" );
bool Close();
private:
HRESULT _hInitRes;
bool _bIsValid;
_ConnectionPtr *_p_pConnection;
};
// CPP
CExtAdoDatabase::CExtAdoDatabase( const char* p_cConnectString, const char* p_cUsername, const char* p_cPwd ) : _hInitRes( CoInitialize( NULL ))
{
_p_pConnection = new _ConnectionPtr( "ADODB.Connection" );
if( FAILED( _hInitRes ))
_bIsValid = false;
else
{
_bIsValid = true;
(*_p_pConnection)->ConnectionTimeout=0;
(*_p_pConnection)->CommandTimeout=0;
if( p_cConnectString != NULL && strlen(p_cConnectString) )
{
_bstr_t scs( p_cConnectString );
_bstr_t susr( p_cUsername );
_bstr_t spwd( p_cPwd );
(*_p_pConnection)->Open( scs, susr, spwd, NULL );
}
}
}
CExtAdoDatabase::~CExtAdoDatabase()
{
Close();
delete _p_pConnection;
CoUninitialize();
}
bool CExtAdoDatabase::Open( const char* p_cConnectString, const char* p_cUsername, const char* p_cPwd )
{
if(_bIsValid)
{
_bstr_t scs( p_cConnectString );
_bstr_t susr( p_cUsername );
_bstr_t spwd( p_cPwd );
return ((*_p_pConnection)->Open( scs, susr, spwd, NULL ) == S_OK);
}
else
return false;
}
bool CExtAdoDatabase::Close()
{
if( _bIsValid )
{
if( (*_p_pConnection)->GetState() == adStateOpen )
return !!(*_p_pConnection)->Close();
else
return true;
}
else
return false;
}
Related
So I have a binary file and its name is being passed into my function as const QString& filename and I'm trying to read it into a ProtoBuf. I have tried the example ParseFromArray(file.data(), file.size()) but it doesn't work and has size 1.
What is the correct way to do this? Thank you!
Here's my relevant code snippet:
bool open(const QString& filename)
{
myProject::protobuf::Example _example;
// need to copy contents from file to _example
}
You need to open the file first using QFile and then read its contents using its inherited method readAll() which will return a QByteArray. Then, use QByteArray::data() and QByteArray::size() to pass to ParseFromArray(const void* data, int size). You also need to take care of the error-handling wherever required.
Here's an example:
bool open( const QString& filename )
{
QFile file { filename };
if ( !file.open( QIODevice::ReadOnly ) ) return false;
const auto data = file.readAll();
if ( data.isEmpty() ) return false;
if ( !ParseFromArray( data.data(), data.size() ) ) return false;
// successful parsing: process here...
return true;
}
My code,
LPSTR Internal::Gz_GetSystemKey( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HW_PROFILE_INFO HwProfInfo;
if (!GetCurrentHwProfile(&HwProfInfo))
{
if(SHOW_ERROR)
Message::Error( "An Internal Error Has Occurred", "Gizmo Message", TRUE );
return NULL;
}
std::string __clean( (char*)HwProfInfo.szHwProfileGuid );
__clean.append( std::string( (char*)HwProfInfo.szHwProfileName ) );
LPSTR neet_key = Crypt::CRC32( Crypt::MD5( (char*)__clean.c_str() ) );
if (SHOW_KEY)
Message::Info( neet_key ); // shows expected result
return neet_key; // returns strange ascii result
};
Gz BOOL Gz_CreateContext( BOOL SHOW_ERROR, BOOL SHOW_KEY ) {
HKEY CHECK; // key result container
BOOL RESULT;
std::wstring neet_key_uni; // must use unicode string in RegSetValueExW
if ( RegOpenKey(HKEY_CURRENT_USER, TEXT("Software\\NEET\\Gizmo\\"), &CHECK) != ERROR_SUCCESS )
goto CREATE_REG_CONTEXT;
else
goto STORE_NEET_KEY;
CREATE_REG_CONTEXT:
if ( RegCreateKeyA( HKEY_CURRENT_USER, "Software\\NEET\\Gizmo\\", &CHECK ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Created" );
RESULT = FALSE;
goto END_MACRO;
}
STORE_NEET_KEY:
LPSTR neet_key = Internal::Gz_GetSystemKey( SHOW_ERROR, SHOW_KEY ); // GetSystemKey generates good key, returns weird ascii
Message::Notify( neet_key );
neet_key_uni = std::wstring(neet_key, neet_key+strlen(neet_key));
if ( RegSetValueEx( CHECK, TEXT("Key"), 0, REG_SZ, (const BYTE*)neet_key_uni.c_str(), ( neet_key_uni.size() + 1 ) * sizeof( wchar_t ) ) != ERROR_SUCCESS ) {
if( SHOW_ERROR )
Message::Error( "Context Could Not Be Reached" );
RESULT = FALSE;
goto END_MACRO;
}
RESULT = TRUE;
END_MACRO:
RegCloseKey(CHECK); // safely close registry key
return RESULT;
};
I'm creating a simple PC identification lib for practice, not for commercial use.
Message::Info( neet_key );
Shows
but the actual return value is
Any ideas why? The 'Message' namespace/functions are just message boxes. As for the 'Crypt' namespace/functions, they aren't the issue at hand.
From the comments: Who owns the memory for the 'neet_key'? My guess would be that the 'Message::Info' shows a valid value because whatever memory structure its from is still in memory but when you return its no longer in memory. Therefore the returned value prints rubbish.
This is a common issue for the C++ language. I would highly recommend that you avoid using raw pointers where possible (especially when returning from functions/methods). For strings you could obviously use 'std::string'.
I have a class named CConfig, I'm creating new object:
std::vector< CConfig > docs;
CConfig newfile( "somefile.xml", "root" );
printf("%s", newfile.GetTagValue( "servername" )); // this works
docs.push_back( newfile );
When I'm getting this object with .at method
CConfig file = docs.at(0);
printf("%s", file.GetTagValue( "servername" )); // this crashes
Where's the problem?
(im sorry if formatting is wrong but currently I don't use javascript because my bandwidth is ended and max speed is 1kb/s so I'll try to fix it later)
CConfig.h:
class CConfig
{
TiXmlDocument m_doc;
TiXmlElement* m_pRoot;
bool m_bIsLoaded;
public:
CConfig ( void ) {};
CConfig ( const char * pszFileName, const char * pszRootName );
~CConfig ( void ) {};
const char* GetTagValue ( const char * pszTagName );
const char* GetTagAttribute ( const char * pszTagName, const char * pszAttributeName );
TiXmlElement* GetRootElement ( void ) { return m_pRoot; };
bool IsAvailable ( void ) { return m_bIsLoaded; };
};
CConfig.cpp
#include "CConfig.h"
CConfig::CConfig( const char * pszFileName, const char * pszRootName )
{
m_bIsLoaded = m_doc.LoadFile( pszFileName );
if( m_bIsLoaded )
m_pRoot = m_doc.FirstChildElement( pszRootName );
}
const char * CConfig::GetTagValue( const char * pszTagName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->GetText();
}
}
const char * CConfig::GetTagAttribute( const char * pszTagName, const char * pszAttributeName )
{
if( m_bIsLoaded && m_pRoot )
{
TiXmlElement * element = m_pRoot->FirstChildElement( pszTagName );
if( element )
return element->Attribute( pszAttributeName );
}
}
I'm using tinyxml
Your issue is with pointers to old memory. When you add an item to an array, it is copied. Later you leave that scope and the original is destroyed, but ask yourself where the pointer in your copy is pointing? Still to the first (now deleted) object's memory. Uh-oh.
The simplest fix (while avoiding large copy operations) is to make m_doc into a shared pointer (available in the standard in C++11, or via Boost in C++03). That will then handle everything for you rule-of-3 wise. And because the underlying memory won't move, m_pRoot will remain valid until the last copy has been deleted.
If copy-space is not an issue, then fix your Rule of Three violation by properly adding a copy constructor:
CConfig(const CConfig& obj)
: m_doc(obj.m_doc)
, m_bLoaded(obj.m_bLoaded)
, m_pRoot()
{
if (m_bLoaded)
m_pRoot = m_doc.GetRootElement();
}
An assignment operator is also likely in order, but if you don't need it, hide it by declaring it (but not implementing it) as private or use the C++11 delete attribute feature.
Interestingly enough, you don't even need the m_bLoaded member. A non-NULL root pointer can indicate your loaded-state, but that is a separate issue. This at least be enough to get you up and running.
I am in the process of writing an application in which I use the Set class in the C++ STL. I've discovered that the call to set->find() always seems to fail when I query for the last element I inserted. However, if I iterate over the set, I am able to see the element I was originally querying for.
To try to get a grasp on what is going wrong, I've created a sample application that exhibits the same behavior that I am seeing. My test code is posted below.
For the actual application itself, I need to store pointers to objects in the set. Is this what is causing the weird behavior. Or is there an operator I need to overload in the class I am storing the pointer of?
Any help would be appreciated.
#include <stdio.h>
#include <set>
using namespace std;
#define MySet set<FileInfo *,bool(*)(const FileInfo *, const FileInfo*)>
class FileInfo
{
public:
FileInfo()
{
m_fileName = 0;
}
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
~FileInfo()
{
if( m_fileName )
{
delete m_fileName;
m_fileName = 0;
}
}
void setFile( const char * file )
{
if( m_fileName )
{
delete m_fileName;
}
m_fileName = new char[ strlen( file ) + 1 ];
strcpy( m_fileName, file );
}
const char * getFile() const
{
return m_fileName;
}
private:
char * m_fileName;
};
bool fileinfo_comparator( const FileInfo * f1, const FileInfo* f2 )
{
if( f1 && ! f2 ) return -1;
if( !f1 && f2 ) return 1;
if( !f1 && !f2 ) return 0;
return strcmp( f1->getFile(), f2->getFile() );
}
void find( MySet *s, FileInfo * value )
{
MySet::iterator iter = s->find( value );
if( iter != s->end() )
{
printf( "Found File[%s] at Item[%p]\n", (*iter)->getFile(), *iter );
}
else
{
printf( "No Item found for File[%s]\n", value->getFile() );
}
}
int main()
{
MySet *theSet = new MySet(fileinfo_comparator);
FileInfo * profile = new FileInfo();
FileInfo * shell = new FileInfo();
FileInfo * mail = new FileInfo();
profile->setFile( "/export/home/lm/profile" );
shell->setFile( "/export/home/lm/shell" );
mail->setFile( "/export/home/lm/mail" );
theSet->insert( profile );
theSet->insert( shell );
theSet->insert( mail );
find( theSet, profile );
FileInfo * newProfile = new FileInfo( *profile );
find( theSet, newProfile );
FileInfo * newMail = new FileInfo( *mail );
find( theSet, newMail );
printf( "\nDisplaying Contents of Set:\n" );
for( MySet::iterator iter = theSet->begin();
iter != theSet->end(); ++iter )
{
printf( "Item [%p] - File [%s]\n", *iter, (*iter)->getFile() );
}
}
The Output I get from this is:
Found File[/export/home/lm/profile] at Item[2d458]
Found File[/export/home/lm/profile] at Item[2d458]
No Item found for File[/export/home/lm/mail]
Displaying Contents of Set:
Item [2d478] - File [/export/home/lm/mail]
Item [2d468] - File [/export/home/lm/shell]
Item [2d458] - File [/export/home/lm/profile]
**Edit
It's kind of sad that I have to add this. But as I mentioned before, this is a sample application that was pulled from different parts of a larger application to exhibit the failure I was receiving.
It is meant as a unit test for calling set::find on a set populated with heap allocated pointers. If you have a problem with all the new()s, I'm open to suggestions on how to magically populate a set with heap allocated pointers without using them. Otherwise commenting on "too many new() calls" will just make you look silly.
Please focus on the actual problem that was occurring (which is now solved). Thanks.
***Edit
Perhaps I should have put these in my original question. But I was hoping there would be more focus on the problem with the find() (or as it turns out fileinfo_comparator function that acts more like strcmp than less), then a code review of a copy-paste PoC unit test.
Here are some points about the code in the full application itself.
FileInfo holds a lot of data along with the filename. It holds SHA1 sums, file size, mod time, system state at last edit, among other things. I have cut out must of it's code for this post. It violates the Rule of 3 in this form (Thanks #Martin York. See comments for wiki link).
The use of char* over std::string was originally chosen because of the use of 3rd_party APIs that accept char*. The app has since evolved from then. Changing this is not an option.
The data inside FileInfo is polled from a named pipe on the system and is stored in a Singleton for access across many threads. (I would have scope issues if I didn't allocate on heap)
I chose to store pointers in the Set because the FileInfo objects are large and constantly being added/removed from the Set. I decided pointers would be better than always copying large structures into the Set.
The if statement in my destructor is needless and a left over artifact from debugging of an issue I was tracking down. It should be pulled out because it is unneeded.
Your comparison function is wrong - it returns bool, not integer as strcmp(3). The return statement should be something like:
return strcmp( f1->getFile(), f2->getFile() ) < 0;
Take a look here.
Also, out of curiosity, why not just use std::set<std::string> instead? STL actually has decent defaults and frees you from a lot of manual memory management.
It looks to me like your FileInfo doesn't work correctly (at least for use in a std::set). To be stored in a std::set, the comparison function should return a bool indicating that the two parameters are in order (true) or out of order (false).
Given what your FileInfo does (badly designed imitation of std::string), you'd probably be better off without it completely. As far as I can see, you can use std::string in its place without any loss of functionality. You're also using a lot of dynamic allocation for no good reason (and leaking a lot of what you allocate).
#include <set>
#include <iostream>
#include <iterator>
#include <string>
int main() {
char *inputs[] = { "/export/home/lm/profile", "/export/home/lm/shell", "/export/home/lm/mail" };
char *outputs[] = {"Found: ", "Could **not** find: "};
std::set<std::string> MySet(inputs, inputs+3);
for (int i=0; i<3; i++)
std::cout
<< outputs[MySet.find(inputs[i]) == MySet.end()]
<< inputs[i] << "\n";
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<std::string>(std::cout, "\n"));
return 0;
}
Edit: even when (or really, especially when) FileInfo is more complex, it shouldn't attempt to re-implement string functionality on its own. It should still use an std::string for the file name, and implement an operator< that works with that:
class FileInfo {
std::string filename;
public:
// ...
bool operator<(FileInfo const &other) const {
return filename < other.filename;
}
FileInfo(char const *name) : filename(name) {}
};
std::ostream &operator(std::ostream &os, FileInfo const &fi) {
return os << fi.filename;
}
int main() {
// std::set<std::string> MySet(inputs, inputs+3);
std:set<FileInfo> MySet(inputs, inputs+3);
// ...
std::copy(MySet.begin(), MySet.end(),
std::ostream_iterator<FileInfo>(std::cout, "\n"));
}
In your constructor:
FileInfo( const FileInfo & file )
{
setFile( file.getFile() );
}
m_fileName seems to be not initialized.
Is there an equivalent to the Java File method isDirectory() in MFC? I tried using this :
static bool isDirectory(CString &path) {
return GetFileAttributes(path) & FILE_ATTRIBUTE_DIRECTORY;
}
but it doesn't seem to work.
CFileFind::IsDirectory()
http://msdn.microsoft.com/en-us/library/scx99850(VS.80).aspx
EDIT:
#include <afxwin.h>
#include <iostream>
using namespace std;
CFileFind finder;
fileName += _T("c:\\aDirName");
if (finder.FindFile(fileName))
{
if (finder.FindNextFIle())
{
if (finder.IsDirectory())
{
// Do directory stuff...
}
}
}
If you change filename to have wildcards, you can do a
while(finder.findNextFile()) {...
to get all matching files.
Sorry for possibly "inconsistency" of answer to question but may be you'll see it useful because anytime I need something like this in Windows I am NOT using MFC but regular Windows API:
//not completely tested but after some debug I'm sure it'll work
bool IsDirectory(LPCTSTR sDirName)
{
//First define special structure defined in windows
WIN32_FIND_DATA findFileData; ZeroMemory(&findFileData, sizeof(WIN32_FIND_DATA));
//after that call WinAPI function finding file\directory
//(don't forget to close handle after all!)
HANDLE hf = ::FindFirstFile(sDirName, &findFileData);
if (hf == INVALID_HANDLE_VALUE) //also predefined value - 0xFFFFFFFF
return false;
//closing handle!
::FindClose(hf);
// true if directory flag in on
return (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
}
MFC solution as requested:
a_FSItem path ot the item to test (examine the CFile::GetStatus() for the needed requirements).
CFileStatus t_aFSItemStat;
CFile::GetStatus( a_FSItem, t_aFSItemStat );
if ( ( t_aFSItemStat.m_attribute & CFile::directory )
return true;
return false;
if you wish to include a volume root as a valid directory just add it to the test
t_aFSItemStat.m_attribute & CFile::volume
Its not MFC, but I use this:
bool IsValidFolder(LPCTSTR pszPath)
{
const DWORD dwAttr = ::GetFileAttributes(pszPath);
if(dwAttr != 0xFFFFFFFF)
{
if((FILE_ATTRIBUTE_DIRECTORY & dwAttr) &&
0 != _tcscmp(_T("."), pszPath) &&
0 != _tcscmp(_T(".."), pszPath))
{
return true;
}
}
return false;
}