Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking us to recommend or find a book, tool, software library, tutorial or other off-site resource are off-topic for Stack Overflow as they tend to attract opinionated answers and spam. Instead, describe the problem and what has been done so far to solve it.
Closed 8 years ago.
Improve this question
My application is a commercial GIS C++ application, and I'm looking for a robust/easy to use connector for Postgresq. (Side note: I also plan to use PostGIS)
Does anyone have any recommendations based on your experience? A plus would be if you have tried out various ones.
I have looked at:
Postgres's C client
pqxx
QSql
EDIT
Also, does anyone know what's a good admin GUI tool? I see a community list here. But there are so many! I'm developing on Windows, and dont mind paying for commercial tools.
Someone in another Stackoverflow post suggested Maestro.
libpq++ is one provide very good connector for PostgreSQL
SQLAPI++ is a C++ library for accessing multiple SQL databases (Oracle, SQL Server, DB2, Sybase, Informix, InterBase, SQLBase, MySQL, PostgreSQL and ODBC, SQLite).
Abstract Database Connector is a C/C++ library for making connections to several databases (MySQL, mSQL, PostgreSQL, Interbase, Informix, BDE, ODBC). It runs on Linux, UNIX, BeOS, and Windows, and a dynamic driver loader for ELF OSes is under development
Navicat is Nice GUI tool for PostgrSQL
Take a look at SOCI. Is an open source lib under Boost Software License (one of the most non-restrictive licenses at all).
This lib is designed especially for C++ with the idea of generic programming and type safety in mind.
SOCI Site
I wrote a wrapper around libpq for our needs. I was a long time Zeoslib (http://sourceforge.net/projects/zeoslib/) but they were riped with problems last I used them, didn't support cached datasets and plain slow.
libpq is very, very fast.
I simply download the Windows version of Postgres, copy all the DLLs to a lib directory and export the calls, include the .h and link accordingly.
I realize this is very low level but I can't emphasize enough the performance increase I'm realizing as a result.
Our application is an accounting/ERP type business application with fairly large install base some with fairly significant concurrent many user base (60, 100 connections)... This has served us very well... You can reply back if you want more details on how we wrap libpq and handle cached updates.
UPDATE:
From a request here are the steps to wrap libpq or make use of it directly under windows.
First, to level set, I use Embarcadero RAD XE these days so the commands that follow are the command line tools that ship with RAD XE. You also need to make sure that your command line tools are in the PATH environment variable if not already. If using Visual Studio, then you will have to work out the equivalent commands. Basically I'm creating a .lib file out of a .DLL
TEST.C is a minimalist test code I wrote to make sure I understood how to use libpq and also to test my success.
1. Put all the DLLs into a directory and copy the include directory.
You do not need to install PostgreSQL using the MSI build to get these DLLs, although that would work too. I copied the DLLs from the binary build. The .H files were also taken from the binary build as well. So my directory looks like this:
include\
libpq-fe.h
postgres_ext.h
libeay32.dll
libiconv-2.dll
libintl-8.dll
libpq.dll
ssleay32.dll
zlib1.dll
2. Create an import library against LIBPQ.DLL as follows:
implib -c -a libpq.lib libpq.dll
should now have a libpq.lib file in the same directory as your DLLs.
3. build the test program (or any program) as follows:
bcc32 test.c -l libpq.lib
test.c
#include <stdio.h>
#include "include/libpq-fe.h"
char *db = "mydatabasename";
char *dbserver = "hostname";
char *uname = "username";
char *pass = "password";
char *SQL = "select * from public.auditlog;";
// char *SQL = "select userid, stationid from public.auditlog";
char buff[200];
PGconn *dbconn;
PGresult *res;
void main(void)
{
int nFields, i, j;
printf("Attempting to Connect to Database Server:\n");
printf("Database: %s\n", db);
printf("Server : %s\n", dbserver);
sprintf(buff, "dbname=%s host=%s port=5432 user=%s password=%s",
db, dbserver, uname, pass);
dbconn = PQconnectdb(buff);
if( PQstatus(dbconn) != CONNECTION_OK )
printf("Connection Failed: %s\n", PQerrorMessage(dbconn) );
else
{
printf("Connected Successfully!\n");
sprintf(buff, "BEGIN; DECLARE my_portal CURSOR FOR %s", SQL);
res = PQexec(dbconn, buff);
if( PQresultStatus(res) != PGRES_COMMAND_OK )
{
printf("Error executing SQL!: %s\n", PQerrorMessage(dbconn) );
PQclear(res);
}
else
{
PQclear(res);
res = PQexec(dbconn, "FETCH ALL in my_portal" );
if( PQresultStatus(res) != PGRES_TUPLES_OK )
{
printf("ERROR, Fetch All Failed: %s", PQerrorMessage(dbconn) );
PQclear(res);
}
else
{
nFields = PQnfields(res);
// Print out the field names
for(i=0; i<nFields; i++ )
printf("%-15s", PQfname(res, i) );
printf("\n");
// Print out the rows
for(i=0; i<PQntuples(res); i++)
{
for(j=0; j<nFields; j++)
printf("%-15s", PQgetvalue(res, i, j) );
printf("\n");
}
res = PQexec(dbconn, "END" );
PQclear(res);
}
}
}
PQfinish(dbconn);
}
Now to access a PostgreSQL system I simply copy the libpq.lib file into any new RAD-XE project and add the libpq.lib to the project. I have wrapped the libpq into a database transport driver that sort of separates my database access code away.
The following screen shot shows a RAD-XE project called ptidb that, in turn, uses libpq to provide PostgreSQL support. I also support SQLite except with SQLite I just compile the database directly.
Then I simply ship the DLLs, listed above, along with my final product making sure the DLLs wind up in the same directory as my product.
This should get you going. If you're also interested in the C++ wrapping I do, let me know and I'll post another update with some of it.
Related
The company I'm working with has a program written in ye olde vb6, which is updated pretty frequently, and most clients run the executable from a mapped network drive. This actually has surprisingly few issues, the biggest of which is automatic updates. Currently the updater program (written in c++) renames the existing exe, then downloads and places the new version into the old version's place. This generally works fine, but in some environments it simply fails.
The solution is running this command from microsoft:
for /f "skip=4 tokens=1" %a in ('net files') do net files %a /close
This command closes all network files that are shared (well... most) and then the updater can replace the exe.
In C++ I can use the System(""); function to run that command, or I could redirect the output of net files, and iterate through the results looking for the particular file in question and run net file /close command to close them. But it would be much much nicer if there were winapi functions that have similar capabilities for better reliability and future safety.
Is there any way for me to programmatically find all network shared files and close relevant ones?
You can programmatically do what net file /close does. Just include lmshare.h and link to Netapi32.dll. You have two functions to use: NetFileEnum to enumerate all open network files (on a given computer) and NetFileClose to close them.
Quick (it assumes program is running on same server and there are not too many open connections, see last paragraph) and dirty (no error checking) example:
FILE_INFO_2* pFiles = NULL;
DWORD nRead = 0, nTotal = 0;
NetFileEnum(
NULL, // servername, NULL means localhost
"c:\\directory\\path", // basepath, directory where VB6 program is
NULL, // username, searches for all users
2, // level, we just need resource ID
(LPBYTE*)&pFiles, // bufptr, need to use a double pointer to get the buffer
MAX_PREFERRED_LENGTH, // prefmaxlen, collect as much as possible
&nRead, // entriesread, number of entries stored in pFiles
&nTotal, // totalentries, ignore this
NULL //resume_handle, ignore this
);
for (int i=0; i < nRead; ++i)
NetFileClose(NULL, pFiles[i].fi2_id);
NetApiBufferFree(pFiles);
Refer to MSDN for details about NetFileEnum and NetFileClose. Note that NetFileEnum may return ERROR_MORE_DATA if more data is available.
I am using librsync library for maintaining file versions. I am not able to open files from a network.
Example (creating signature file):
int main(int argc, char** argv)//FILE *original, FILE *signature)
{
if(argc != 2)
{
cout<<"Enter the original file name."<<endl;
exit(1);
}
FILE *fpa;
fpa = fopen(argv[1],"r");
if(fpa==NULL)
{
cout<<"ERROR"<<endl;
exit(1);
}
FILE *fps;
fps = fopen("sig.sig","w+");
rs_result res = rs_sig_file(fpa, fps, 1,2,NULL);
fclose(fpa);
fclose(fps);
printf("Result code: %d\n", res);
return 0;
}
When I run the program with argument of a file over a network, e.g.
./a.out cs1130218#palasi.cse.iitd.ernet.in:games.txt
fpa is NULL.
I guess that fopen is not made for opening files over a network. I need a command which can do this. Any command in c/c++.
You can clearly see what I want to do with the programme.
"I need a command which can open files over a network" is a really, really high-level operation, and as such, it glosses over all kinds of details: What kind of network protocol should be used? How should authentication be handled? How should network errors be handled? What should be done once the file is opened: read / write / both, sequential or random?
librsync is relatively low-level and doesn't even try to answer these questions itself. Its README explains:
librsync does not implement the rsync wire protocol. If you want to talk to an rsync server to transfer files you'll need to shell out to rsync. librsync is for building other programs that transfer files as efficiently as rsync. You can use librsync to make backup tools, distribute binary patches to programs, or sync directories to a server or between peers.
To open files over a network, you'll need to implement your own server and wire protocol, or you'll need to shell out to commands like rsync that handle these details for you (and, if most of your logic is in shelling out to other commands, C++ may not be the best tool for the job).
Neither librsync nor fopen deal with remote files.
Look at using a virtual filesystem library like GVFS or KIO instead: these can open files over SFTP and you can then pass them to librsync.
I've been going trough tons of articles and forums about this and I still have not found my solution. Even though there are several posts of this on this website aswell.
They state these things as answers:
Install this: http://www.microsoft.com/en-us/download/details.aspx?id=13255
I'm unable to install the x86 version, becouse I have office x64 2010. I did however installed the x64 version of that package.
Install this http://www.microsoft.com/en-us/download/details.aspx?id=23734
I've tried it, no results.
Make sure you application is targeted correctly (i.e. x86)
I'm 100% sure my application is 32 bit.
My work environment is as follows:
Visual Studio 2012 professional
Coding language is C++
Microsoft Office 2010
Windows 8 x64
This is the code that I'm using:
class Credential
{
public:
TCHAR CredentialID[3];
TCHAR CredentialName[255];
BEGIN_COLUMN_MAP(Credential)
COLUMN_ENTRY(1, CredentialID)
COLUMN_ENTRY(2, CredentialName)
END_COLUMN_MAP()
};
and this:
try
{
CDataSource ds;
CSession session;
ATL::CCommand<CAccessor<Credential>> cust;
HRESULT hr = CoInitialize(0);
if(FAILED(hr))
{
Console_Output("Can't start COM!?\n");
return;
}
hr = ds.OpenFromInitializationString(L"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=MPFDatabase.accdb;");
Console_Output("%d\n", hr);
if(FAILED(hr))
{
Console_Output("Can't open Nwind\n");
return;
}
hr = session.Open(ds);
if(FAILED(hr))
{
Console_Output("Can't open Nwind SESSION\n");
ds.Close();
return;
}
TCHAR mySQL[] = "SELECT * FROM Credential";
hr = cust.Open(session, mySQL);
if(FAILED(hr))
{
Console_Output("Can't open Nwind TABLE\n");
session.Close();
ds.Close();
return;
}
while(cust.MoveNext() == S_OK)
{
Console_Output("%s -- %s\n", cust.CredentialID, cust.CredentialName);
}
cust.Close();
session.Close();
ds.Close();
}
catch(std::exception &Ex)
{
Console_Output("ex: %s\n", Ex.what());
}
I get to the point where it calls ds.OpenFromInitializationString but then it either stops my application without any notification whatsoever (no exception too). Or I get to the point where it would print in my console "Can't open Nwind\n".
These 2 results depend on what I've installed of the suggested answers.
I've tried absolute and relative paths for my Data Source.
I'm 100% sure it is not locked or something similar. I've created the database myself and it consists of only 2 tables, nothing special.
If I list my providers in windows powershell I get these providers:
SQLOLEDB
MSQLAP
MSQLAP
MSDataShape
SQLNCLI11
Microsoft.ACE.OLEDB.12.0
ADsDSOObject
SQLNCLI11 Enumerator
Windows Search Data Source
MSDASQL
MSDASQL Enumerator
SQLOLEDB Enumerator
MSDAOSP
So the ace engine is indeed installed as you can see.
EDIT:
Forgot to mention that it is concerning a local accdb file made in ms access 2010 on my computer. In case that wasn't clear.
As Gord has said. . .
How do you have a 32 bit application running on a 64 bit machine? First thing is to try to get those in sync.
I had a similar problem with access (but the application type was setup properly for me and I was in c#) so I will mention the three things that had an affect relating to the compatability problem as we had the same error message.
Goto the properties tab under Build. Then change Platform Target from the default Any CPU to x64 or x86. For me this was not optional it must be set to the right one when I deployed, but it worked fine under any CPU when I was debugging locally.
I also had to install the AccessDataBaseEngine_x64 which it sounds like you have already.
The next thing to check is your connection string.
For me my local was x86 and my server was x64.
For me both of these two worked with some playing around on this Jet and ACE settings:
string connectionString = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\your pathj\Database.accdb;";
string connectionString = #"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\your path\Database.accdb;Jet OLEDB:Database Password=password";
and I passed the connectionString instead of putting it into the field directly.
Hope this helps.
If you have the 64-bit version of the Access Database Engine -- a.k.a. "ACE" -- installed (as part of 64-bit Office 2010) and you are 100% sure that your application is running as 32-bit then I'm 100% sure that it won't work. 32-bit applications cannot use the 64-bit ACE driver, and 64-bit applications cannot use the 32-bit ACE driver. So, your choices are:
configure your application to run as 64-bit and use the existing 64-bit ACE driver, or
replace the 64-bit version of Office with the 32-bit version and run your application as 32-bit.
I am connecting to a mysql database using the embedding server (linking against mysqld) in c++. I have the following code:
static char *server_options[] = \
{ (char *)"mysql_test",
(char *)"--datadir=/home/cquiros/temp/mysql/db2",
(char *)"--default-storage-engine=MyISAM",
(char *)"--loose-innodb=0",
(char *)"--local-infile=1",
(char *)"--skip-grant-tables=1",
(char *)"--myisam-recover=FORCE",
(char *)"--key_buffer_size=16777216",
(char *)"--character-set-server=utf8",
(char *)"--collation-server=utf8_bin",
NULL };
int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;
mysql_library_init(num_elements, server_options, NULL);
m_mysql = mysql_init(NULL);
char enable_load_infile = 1;
if (mysql_options(m_mysql,MYSQL_OPT_LOCAL_INFILE, (const char *)&(enable_load_infile)))
qDebug() << "Error setting option";
mysql_real_connect(m_mysql, NULL,NULL,NULL, "database1", 0,NULL,0);
The connection works and I can query and create tables however, when I try to execute "load data local infile ..." I always get "The used command is not allowed with this MySQL version" even though I am setting --local-infile=1 in the server options or setting it in code in:
char enable_load_infile = 1;
if (mysql_options(m_mysql,MYSQL_OPT_LOCAL_INFILE, (const char *)&(enable_load_infile)))
qDebug() << "Error setting option";
Any idea what I am doing wrong and how to fix it?
Many thanks for your help.
Carlos.
#QLands I realize its over a year since you've asked this question, but I figured I'd reply just for posterity in case others like me are googling for solutions.
I'm having the same issue, I can get LOAD DATA LOCAL INFILE statements to work from the Linux mysql CLI after I explicitly enabled it in the /etc/mysql/my.cfg file. However I CANNOT get it to work with the MySQL C++ connector -- I also get the error "The used command is not allowed with this MySQL version" when I try and run a LOAD DATA LOCAL INFILE command through the MySQL C++ connector. wtf right?
After much diligent googling and finding some back alley tech support posts I've come to conclude that the MySQL C++ connector did not (for whatever reason) decide to implement the ability for developers to be able to allow the local-infile=1 option. Apparently some people have been able to hack/fork the MySQL C++ connector to expose the functionality, but no one posted their source code -- only said it worked. Apparently there is a workaround in the MySQL C API after you initialize the connection you would use this:
mysql_options( &mysql, MYSQL_OPT_LOCAL_INFILE, 1 );
Here are some reference articles that lead me to this conclusion:
1.)
How can I get the native C API connection structure from MySQL Connector/C++?
2.)
Mysql 5.5 LOAD DATA INFILE Permissions
3.)
http://osdir.com/ml/db.mysql.c++/2004-04/msg00097.html
Essentially if you want the ability to use the LOAD DATA LOCAL INFILE functionality -- you have to use the mysql C API or execute it from the command line or hack/fork the existing mysql C++ api to expose the connection structure
:(
Using C++ on the Linux desktop, what is the best way to get the icon, the document description and the application "associated" with an arbitrary file/file path?
I'd like to use the most "canonical" way to find icons, mime-type/file type descriptions and associated applications on both KDE and gnome and I'd like to avoid any "shelling out" to the command line and "low-level" routines as well as avoiding re-inventing the wheel myself (no parsing the mime-types file and such).
Edits and Notes:
Hey, I originally asked this question about the QT file info object and the answer that "there is no clear answer" seems to be correct as far as it goes. BUT this is such a screwed-up situation that I am opening the question looking for more information.
I don't care about QT in particular any more, I'm just looking for the most cannonical way to find the mime type via C++/c function calls on both KDE and gnome (especially Gnome, since that's where things confuse me most). I want to be able show icons and descriptions matching Nautilus in Gnome and Konquerer/whatever on KDE as well as opening files appropriately, etc.
I suppose it's OK that I get this separately for KDE and Gnome. The big question is what's the most common/best/cannonical way to get all this information for the Linux desktop? Gnome documentation is especially opaque. gnome-vsf has mime routines but it's deprecated and I can't find a mime routine for GIO/GFS, gnome-vsf's replacement. There's a vague implication that one should use the open desktop applications but which one to use is obscure. And where does libmagic and xdg fit in?
Pointers to an essay summarizing the issues gladly accepted. Again, I know the three line answer is "no such animal" but I'm looking for the long answer.
Here is an example of using GLib/GIO to get the information you want.
#include <gio/gio.h>
#include <stdio.h>
int
main (int argc, char **argv)
{
g_thread_init (NULL);
g_type_init ();
if (argc < 2)
return -1;
GError *error;
GFile *file = g_file_new_for_path (argv[1]);
GFileInfo *file_info = g_file_query_info (file,
"standard::*",
0,
NULL,
&error);
const char *content_type = g_file_info_get_content_type (file_info);
char *desc = g_content_type_get_description (content_type);
GAppInfo *app_info = g_app_info_get_default_for_type (
content_type,
FALSE);
/* you'd have to use g_loadable_icon_load to get the actual icon */
GIcon *icon = g_file_info_get_icon (file_info);
printf ("File: %s\nDescription: %s\nDefault Application: %s\n",
argv[1],
desc,
g_app_info_get_executable (app_info));
return 0;
}
You can use the tools available from xdg for that, in particular xdg-mime query.
To find out the filetype of e.g. a file index.html you would
$ xdg-mime query filetype index.html
This will return the mimetype. To query what application is associated with that mimetye use e.g.
$ xdg-mime query default text/html
This returns epiphany.desktop here, i.e. $APPNAME.desktop, so it is easy to get the application name from it. If you would just want to open the file in the default app you could of course just run
$ xdg-open index.html
which would fire up epiphany.
Query functions for icon resources do not seem to be available in xdg-utils, but you could write a small python script using pyxdg that offers tons of additional functionality, too.
For C bindings you will probably need to have a look into the portland code linked on the xdg page.
EDIT:
Concerning libmagic and friends, you will need to decide on your preferences: While libmagic seems to be more complete (and accurate) in terms of coverage for filetypes, it does not care at all about default applications or icons. It also does not provide you with tools to install extra mimetypes.
In Qt >= 4.6, there is a new function for X11 systems
QIcon QIcon::fromTheme ( const QString & name, const QIcon & fallback = QIcon() ) [static]
You can use this function. Documentation here / (Qt 5)
Neither QFileIconProvider nor QFileInfo will do anything with the OS mime database. To access icons associated with different mime types, you will have to use functions of the underlying desktop environment. In Qt there is (yet) no canonical way.
Consider you can have a different icon in Gnome, in KDE and in Windows. So for instance, in KDE you would use KMimeType.
I just found KFileItem. This class gives you everything you for icons, mime types and related things in KDE. I'm sure that there's an equivalent in gnome but this gives access at the same level as a QT application works.
You may want to use the system's "/etc/mime.types" file. It is also a good idea to maintain your program's copy of a MIME type file. That way, you are not dependent on the system, but at the same time you need to keep it fairly exhaustive. Not sure about Icons.
Maybe take a look at this code:
http://ftp.devil-linux.org/pub/devel/sources/1.2/file-4.23.tar.gz
This is the standard file util found on most Linux/Unix distributions. You will get the MIME-type and some more information.
I think both Gnome and KDE have their own ways to determine this and also to set the icon and the standard application for it.
Anyway, that file-tool is probably the best way to get the mime type and the document description. And in some cases even some details about the content.
This will get you the mime-type. That is what you need anyway to know how you can open the file. These are seperated steps. file doesn't say you about the icon nor the application to open the file with.
About 8 years late, but still useful.
To get the associated applications in KDE you can do what Joe suggested (using KFileItem). However, that requires inclusion of a lot of libraries.
The code below requires less.
#include <QCoreApplication>
#include <QMimeDatabase>
#include <QDebug>
#include <KMimeTypeTrader>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
if (argc < 2)
{
qDebug() << "missing argument <filename>";
return 1;
}
QMimeDatabase mimeDb;
QMimeType mimeType = mimeDb.mimeTypeForFile(QString::fromLocal8Bit(argv[1]));
KService::List services = KMimeTypeTrader::self()->query(
mimeType.name(),QStringLiteral("Application"));
foreach(const QExplicitlySharedDataPointer<KService>& svc, services)
{
qDebug() << "service: " << svc->name();
qDebug() << "exec: " << svc->exec();
}
}
To compile the code add QT += KService KCoreAddons to your qmake .pro file.
Links to KMimeTypeTrader & KService documentation:
https://api.kde.org/frameworks/kservice/html/classKService.html
https://api.kde.org/frameworks/kservice/html/classKMimeTypeTrader.html
Copy/Paste of the nice example above (using GLib/Gio) just added proper release of allocated memory as per documentation. I tried to just edit the existing answer but it kept saying the edit queue was full :(
#include <gio/gio.h>
#include <stdio.h>
int
main (int argc, char **argv)
{
g_thread_init (NULL);
g_type_init ();
if (argc < 2)
return -1;
g_autoptr(GError) error;
GFile* file = g_file_new_for_path (argv[1]);
GFileInfo* file_info = g_file_query_info (file,
"standard::*",
G_FILE_QUERY_INFO_NONE,
NULL,
&error);
const char* content_type = g_file_info_get_content_type (file_info);
g_autofree gchar* desc = g_content_type_get_description (content_type);
GAppInfo* app_info = g_app_info_get_default_for_type (
content_type,
FALSE);
/* you'd have to use g_loadable_icon_load to get the actual icon */
GIcon* icon = g_file_info_get_icon (file_info);
printf ("File: %s\nDescription: %s\nDefault Application: %s\n",
argv[1],
desc,
g_app_info_get_executable (app_info));
g_object_unref(file_info);
g_object_unref(file);
return 0;
}