Skip to content

Commit

Permalink
Improve parsing in QgsDataSourceURI (adapted from PQconnectdb) and ga…
Browse files Browse the repository at this point in the history
…ther

connection info parsing and creation there.   Fixes #817.

Please test!



git-svn-id: http://svn.osgeo.org/qgis/trunk@7672 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
jef committed Nov 27, 2007
1 parent eac2a5f commit 4652d5a
Show file tree
Hide file tree
Showing 11 changed files with 418 additions and 395 deletions.
39 changes: 14 additions & 25 deletions python/core/qgsdatasourceuri.sip
Expand Up @@ -19,8 +19,14 @@ public:
//! constructor which parses input URI //! constructor which parses input URI
QgsDataSourceURI(QString uri); QgsDataSourceURI(QString uri);


//! All in a single string //! connection info
QString text() const; QString connInfo() const;

//! complete uri
QString uri() const;

//! quoted table name
QString quotedTablename() const;


//! Set all connection related members at once //! Set all connection related members at once
void setConnection(const QString& aHost, void setConnection(const QString& aHost,
Expand All @@ -35,28 +41,11 @@ public:
const QString& aGeometryColumn, const QString& aGeometryColumn,
const QString& aSql = QString()); const QString& aSql = QString());


/* data */ QString username() const;
QString schema() const;
QString table() const;
QString sql() const;
QString geometryColumn() const;


//! host name void setSql(QString sql);
QString host;
//! database name
QString database;
//! port the database server listens on
QString port;
//! schema
QString schema;
//! spatial table
QString table;
//! geometry column
QString geometryColumn;
//! SQL where clause used to limit features returned from the layer
QString sql;
//! username
QString username;
//! password
QString password;

//! whole connection info (host, db, port, name, pass)
QString connInfo;
}; };

38 changes: 17 additions & 21 deletions src/app/qgsdbsourceselect.cpp
Expand Up @@ -25,6 +25,7 @@ email : sherman at mrcc.com
#include "qgscontexthelp.h" #include "qgscontexthelp.h"
#include "qgsnewconnection.h" #include "qgsnewconnection.h"
#include "qgspgquerybuilder.h" #include "qgspgquerybuilder.h"
#include "qgsdatasourceuri.h"


#include <QInputDialog> #include <QInputDialog>
#include <QMessageBox> #include <QMessageBox>
Expand Down Expand Up @@ -351,45 +352,40 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
// populate the table list // populate the table list
QSettings settings; QSettings settings;


bool makeConnection = true;
QString key = "/PostgreSQL/connections/" + cmbConnections->currentText(); QString key = "/PostgreSQL/connections/" + cmbConnections->currentText();
QString connString = "host=";
QString host = settings.readEntry(key + "/host");
connString += host;
connString += " dbname=";
QString database = settings.readEntry(key + "/database"); QString database = settings.readEntry(key + "/database");
connString += database + " port=";
QString port = settings.readEntry(key + "/port");
if(port.length() == 0)
{
port = "5432";
}
connString += port + " user=";
QString username = settings.readEntry(key + "/username"); QString username = settings.readEntry(key + "/username");
connString += username;
QString password = settings.readEntry(key + "/password"); QString password = settings.readEntry(key + "/password");
bool searchPublicOnly = settings.readBoolEntry(key + "/publicOnly");
bool searchGeometryColumnsOnly = settings.readBoolEntry(key + "/geometryColumnsOnly");
bool makeConnection = true;
if (password == QString::null) if (password == QString::null)
{ {
// get password from user // get password from user
makeConnection = false; makeConnection = false;
QString password = QInputDialog::getText(tr("Password for ") + database + "@" + host, QString password = QInputDialog::getText(tr("Password for ") + username,
tr("Please enter your password:"), tr("Please enter your password:"),
QLineEdit::Password, QString::null, &makeConnection, this); QLineEdit::Password, QString::null, &makeConnection, this);
// allow null password entry in case its valid for the database // allow null password entry in case its valid for the database
} }


QgsDataSourceURI uri;
uri.setConnection( settings.readEntry(key + "/host"),
settings.readEntry(key + "/port"),
database,
settings.readEntry(key + "/username"),
password );

bool searchPublicOnly = settings.readBoolEntry(key + "/publicOnly");
bool searchGeometryColumnsOnly = settings.readBoolEntry(key + "/geometryColumnsOnly");

// Need to escape the password to allow for single quotes and backslashes // Need to escape the password to allow for single quotes and backslashes
password.replace('\\', "\\\\");
password.replace('\'', "\\'");
connString += " password='" + password + "'";


QgsDebugMsg("Connection info: " + connString); QgsDebugMsg("Connection info: " + uri.connInfo());


if (makeConnection) if (makeConnection)
{ {
m_connInfo = connString; //host + " " + database + " " + username + " " + password; m_connInfo = uri.connInfo();
//qDebug(m_connInfo); //qDebug(m_connInfo);
// Tidy up an existing connection if one exists. // Tidy up an existing connection if one exists.
if (pd != 0) if (pd != 0)
Expand Down
78 changes: 36 additions & 42 deletions src/app/qgsnewconnection.cpp
Expand Up @@ -22,6 +22,9 @@


#include "qgsnewconnection.h" #include "qgsnewconnection.h"
#include "qgscontexthelp.h" #include "qgscontexthelp.h"
#include "qgsdatasourceuri.h"
#include "qgslogger.h"

extern "C" extern "C"
{ {
#include <libpq-fe.h> #include <libpq-fe.h>
Expand All @@ -31,38 +34,38 @@ QgsNewConnection::QgsNewConnection(QWidget *parent, const QString& connName, Qt:
{ {
setupUi(this); setupUi(this);
if (!connName.isEmpty()) if (!connName.isEmpty())
{ {
// populate the dialog with the information stored for the connection // populate the dialog with the information stored for the connection
// populate the fields with the stored setting parameters // populate the fields with the stored setting parameters
QSettings settings; QSettings settings;


QString key = "/PostgreSQL/connections/" + connName; QString key = "/PostgreSQL/connections/" + connName;
txtHost->setText(settings.readEntry(key + "/host")); txtHost->setText(settings.readEntry(key + "/host"));
txtDatabase->setText(settings.readEntry(key + "/database")); txtDatabase->setText(settings.readEntry(key + "/database"));
QString port = settings.readEntry(key + "/port"); QString port = settings.readEntry(key + "/port");
if(port.length() ==0){ if(port.length() ==0){
port = "5432"; port = "5432";
} }
txtPort->setText(port); txtPort->setText(port);
txtUsername->setText(settings.readEntry(key + "/username")); txtUsername->setText(settings.readEntry(key + "/username"));
Qt::CheckState s = Qt::Checked; Qt::CheckState s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/publicOnly", false)) if ( ! settings.readBoolEntry(key + "/publicOnly", false))
s = Qt::Unchecked; s = Qt::Unchecked;
cb_publicSchemaOnly->setCheckState(s); cb_publicSchemaOnly->setCheckState(s);
s = Qt::Checked; s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/geometrycolumnsOnly", false)) if ( ! settings.readBoolEntry(key + "/geometrycolumnsOnly", false))
s = Qt::Unchecked; s = Qt::Unchecked;
cb_geometryColumnsOnly->setCheckState(s); cb_geometryColumnsOnly->setCheckState(s);
// Ensure that cb_plublicSchemaOnly is set correctly // Ensure that cb_plublicSchemaOnly is set correctly
on_cb_geometryColumnsOnly_clicked(); on_cb_geometryColumnsOnly_clicked();


if (settings.readEntry(key + "/save") == "true") if (settings.readEntry(key + "/save") == "true")
{ {
txtPassword->setText(settings.readEntry(key + "/password")); txtPassword->setText(settings.readEntry(key + "/password"));
chkStorePassword->setChecked(true); chkStorePassword->setChecked(true);
}
txtName->setText(connName);
} }
txtName->setText(connName);
}
} }
/** Autoconnected SLOTS **/ /** Autoconnected SLOTS **/
void QgsNewConnection::on_btnOk_clicked() void QgsNewConnection::on_btnOk_clicked()
Expand Down Expand Up @@ -96,21 +99,12 @@ QgsNewConnection::~QgsNewConnection()
} }
void QgsNewConnection::testConnection() void QgsNewConnection::testConnection()
{ {
// following line uses Qt SQL plugin - currently not used QgsDataSourceURI uri;
// QSqlDatabase *testCon = QSqlDatabase::addDatabase("QPSQL7","testconnection"); uri.setConnection( txtHost->text(), txtPort->text(), txtDatabase->text(), txtUsername->text(), txtPassword->text() );


// Need to escape the password to allow for single quotes and backslashes QgsLogger::debug( "PQconnectdb(" + uri.connInfo() + ");" );
QString password = txtPassword->text();
password.replace('\\', "\\\\");
password.replace('\'', "\\'");


QString connInfo = PGconn *pd = PQconnectdb( uri.connInfo().toLocal8Bit().data() );
"host=" + txtHost->text() +
" dbname=" + txtDatabase->text() +
" port=" + txtPort->text() +
" user=" + txtUsername->text() +
" password='" + password + "'";
PGconn *pd = PQconnectdb(connInfo.toLocal8Bit().data());
// std::cout << pd->ErrorMessage(); // std::cout << pd->ErrorMessage();
if (PQstatus(pd) == CONNECTION_OK) if (PQstatus(pd) == CONNECTION_OK)
{ {
Expand Down
64 changes: 15 additions & 49 deletions src/app/qgspgquerybuilder.cpp
Expand Up @@ -34,28 +34,21 @@ QgsPgQueryBuilder::QgsPgQueryBuilder(QgsDataSourceURI *uri,
setupUi(this); setupUi(this);
// The query builder must make its own connection to the database when // The query builder must make its own connection to the database when
// using this constructor // using this constructor
QString connInfo = QString("host=%1 dbname=%2 port=%3 user=%4 password=%5") QString connInfo = mUri->connInfo();
.arg(mUri->host)
.arg(mUri->database) QgsDebugMsg("Attempting connect using: " + connInfo);
.arg(mUri->port)
.arg(mUri->username)
.arg(mUri->password);
#ifdef QGISDEBUG
std::cerr << "Attempting connect using: " << connInfo.toLocal8Bit().data() << std::endl;
#endif
mPgConnection = PQconnectdb(connInfo.toLocal8Bit().data()); mPgConnection = PQconnectdb(connInfo.toLocal8Bit().data());
// check the connection status // check the connection status
if (PQstatus(mPgConnection) == CONNECTION_OK) { if (PQstatus(mPgConnection) == CONNECTION_OK) {
QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>")) QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>"))
.arg(mUri->table) .arg(mUri->table() )
.arg(PQdb(mPgConnection)) .arg(PQdb(mPgConnection))
.arg(PQhost(mPgConnection)) .arg(PQhost(mPgConnection))
.arg(PQuser(mPgConnection)); .arg(PQuser(mPgConnection));
mOwnConnection = true; // we own this connection since we created it mOwnConnection = true; // we own this connection since we created it
// tell the DB that we want text encoded in UTF8 // tell the DB that we want text encoded in UTF8
PQsetClientEncoding(mPgConnection, "UNICODE"); PQsetClientEncoding(mPgConnection, "UNICODE");
// and strip any quotation as this code does it's own quoting.
trimQuotation();


lblDataUri->setText(datasource); lblDataUri->setText(datasource);
populateFields(); populateFields();
Expand All @@ -77,22 +70,12 @@ QgsPgQueryBuilder::QgsPgQueryBuilder(QString tableName, PGconn *con,
{ {
setupUi(this); setupUi(this);
mOwnConnection = false; // we don't own this connection since it was passed to us mOwnConnection = false; // we don't own this connection since it was passed to us
mUri = new QgsDataSourceURI(); mUri = new QgsDataSourceURI( "table=" + tableName);
QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>")) QString datasource = QString(tr("Table <b>%1</b> in database <b>%2</b> on host <b>%3</b>, user <b>%4</b>"))
.arg(tableName) .arg(tableName)
.arg(PQdb(mPgConnection)) .arg(PQdb(mPgConnection))
.arg(PQhost(mPgConnection)) .arg(PQhost(mPgConnection))
.arg(PQuser(mPgConnection)); .arg(PQuser(mPgConnection));
// populate minimum uri fields needed for the populate fields function
QRegExp reg("\"(.+)\"\\.\"(.+)\"");
reg.indexIn(tableName);
QStringList parts = reg.capturedTexts(); // table name contains table and schema
mUri->schema = parts[1];
// strip whitespace to make sure the table name is clean
mUri->table = parts[2];

// and strip any quotation as this code does it's own quoting.
trimQuotation();


lblDataUri->setText(datasource); lblDataUri->setText(datasource);
populateFields(); populateFields();
Expand All @@ -109,7 +92,7 @@ void QgsPgQueryBuilder::populateFields()
{ {
// Populate the field vector for this layer. The field vector contains // Populate the field vector for this layer. The field vector contains
// field name, type, length, and precision (if numeric) // field name, type, length, and precision (if numeric)
QString sql = "select * from \"" + mUri->schema + "\".\"" + mUri->table + "\" limit 1"; QString sql = "select * from " + mUri->quotedTablename() + " limit 1";
PGresult *result = PQexec(mPgConnection, (const char *) (sql.utf8())); PGresult *result = PQexec(mPgConnection, (const char *) (sql.utf8()));
QgsLogger::debug("Query executed: " + sql); QgsLogger::debug("Query executed: " + sql);
if (PQresultStatus(result) == PGRES_TUPLES_OK) if (PQresultStatus(result) == PGRES_TUPLES_OK)
Expand Down Expand Up @@ -152,38 +135,22 @@ void QgsPgQueryBuilder::populateFields()
mFieldMap[fieldName] = QgsField(fieldName, type, fieldType); mFieldMap[fieldName] = QgsField(fieldName, type, fieldType);
lstFields->insertItem(fieldName); lstFields->insertItem(fieldName);
} }
}else }
else
{ {
#ifdef QGISDEBUG QgsDebugMsg( "Error fetching a row from " + mUri->table() );
std::cerr << "Error fetching a row from " << mUri->table.toLocal8Bit().data() << std::endl;
#endif
} }
PQclear(result); PQclear(result);
} }


void QgsPgQueryBuilder::trimQuotation()
{
// Trim " characters that may be surrounding the table and schema name
if (mUri->schema.at(0) == '"')
{
mUri->schema.remove(mUri->schema.length()-1, 1);
mUri->schema.remove(0, 1);
}
if (mUri->table.at(0) == '"')
{
mUri->table.remove(mUri->table.length()-1, 1);
mUri->table.remove(0, 1);
}
}

void QgsPgQueryBuilder::on_btnSampleValues_clicked() void QgsPgQueryBuilder::on_btnSampleValues_clicked()
{ {
if (lstFields->currentText().isEmpty()) if (lstFields->currentText().isEmpty())
return; return;


QString sql = "SELECT DISTINCT \"" + lstFields->currentText() + "\" " + QString sql = "SELECT DISTINCT \"" + lstFields->currentText() + "\" " +
"FROM (SELECT \"" + lstFields->currentText() + "\" " + "FROM (SELECT \"" + lstFields->currentText() + "\" " +
"FROM \"" + mUri->schema + "\".\"" + mUri->table + "\" " + "FROM " + mUri->quotedTablename() + " " +
"LIMIT 5000) AS foo " + "LIMIT 5000) AS foo " +
"ORDER BY \"" + lstFields->currentText() + "\" "+ "ORDER BY \"" + lstFields->currentText() + "\" "+
"LIMIT 25"; "LIMIT 25";
Expand Down Expand Up @@ -224,7 +191,7 @@ void QgsPgQueryBuilder::on_btnGetAllValues_clicked()
return; return;


QString sql = "select distinct \"" + lstFields->currentText() QString sql = "select distinct \"" + lstFields->currentText()
+ "\" from \"" + mUri->schema + "\".\"" + mUri->table + "\" order by \"" + lstFields->currentText() + "\""; + "\" from " + mUri->quotedTablename() + " order by \"" + lstFields->currentText() + "\"";
// clear the values list // clear the values list
lstValues->clear(); lstValues->clear();
// determine the field type // determine the field type
Expand Down Expand Up @@ -272,8 +239,8 @@ void QgsPgQueryBuilder::on_btnTest_clicked()
else else
{ {
QString numRows; QString numRows;
QString sql = "select count(*) from \"" + mUri->schema + "\".\"" + mUri->table QString sql = "select count(*) from " + mUri->quotedTablename()
+ "\" where " + txtSQL->text(); + " where " + txtSQL->text();
PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8())); PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));
if (PQresultStatus(result) == PGRES_TUPLES_OK) if (PQresultStatus(result) == PGRES_TUPLES_OK)
{ {
Expand All @@ -297,8 +264,7 @@ void QgsPgQueryBuilder::on_btnTest_clicked()
// XXX This should really throw an exception // XXX This should really throw an exception
long QgsPgQueryBuilder::countRecords(QString where) long QgsPgQueryBuilder::countRecords(QString where)
{ {
QString sql = "select count(*) from \"" + mUri->schema + "\".\"" + mUri->table QString sql = "select count(*) from " + mUri->quotedTablename() + " where " + where;
+ "\" where " + where;


long numRows; long numRows;
PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8())); PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));
Expand Down
5 changes: 0 additions & 5 deletions src/app/qgspgquerybuilder.h
Expand Up @@ -119,11 +119,6 @@ class QgsPgQueryBuilder : public QDialog, private Ui::QgsPgQueryBuilderBase {
*/ */
void populateFields(); void populateFields();


/*!
* Trims surround " characters from the schema and table name
*/
void trimQuotation();

/*! Get the number of records that would be returned by the current SQL /*! Get the number of records that would be returned by the current SQL
* @return Number of records or -1 if an error was encountered * @return Number of records or -1 if an error was encountered
*/ */
Expand Down

0 comments on commit 4652d5a

Please sign in to comment.