Improve parsing in QgsDataSourceURI (adapted from PQconnectdb) and gather

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
This commit is contained in:
jef 2007-11-27 21:35:10 +00:00
parent eac2a5f47a
commit 4652d5acf5
11 changed files with 435 additions and 412 deletions

View File

@ -19,8 +19,14 @@ public:
//! constructor which parses input URI
QgsDataSourceURI(QString uri);
//! All in a single string
QString text() const;
//! connection info
QString connInfo() const;
//! complete uri
QString uri() const;
//! quoted table name
QString quotedTablename() const;
//! Set all connection related members at once
void setConnection(const QString& aHost,
@ -35,28 +41,11 @@ public:
const QString& aGeometryColumn,
const QString& aSql = QString());
/* data */
QString username() const;
QString schema() const;
QString table() const;
QString sql() const;
QString geometryColumn() const;
//! host name
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;
void setSql(QString sql);
};

View File

@ -25,6 +25,7 @@ email : sherman at mrcc.com
#include "qgscontexthelp.h"
#include "qgsnewconnection.h"
#include "qgspgquerybuilder.h"
#include "qgsdatasourceuri.h"
#include <QInputDialog>
#include <QMessageBox>
@ -351,45 +352,40 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
// populate the table list
QSettings settings;
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");
connString += database + " port=";
QString port = settings.readEntry(key + "/port");
if(port.length() == 0)
{
port = "5432";
}
connString += port + " user=";
QString username = settings.readEntry(key + "/username");
connString += username;
QString password = settings.readEntry(key + "/password");
bool searchPublicOnly = settings.readBoolEntry(key + "/publicOnly");
bool searchGeometryColumnsOnly = settings.readBoolEntry(key + "/geometryColumnsOnly");
bool makeConnection = true;
QString key = "/PostgreSQL/connections/" + cmbConnections->currentText();
QString database = settings.readEntry(key + "/database");
QString username = settings.readEntry(key + "/username");
QString password = settings.readEntry(key + "/password");
if (password == QString::null)
{
// get password from user
makeConnection = false;
QString password = QInputDialog::getText(tr("Password for ") + database + "@" + host,
QString password = QInputDialog::getText(tr("Password for ") + username,
tr("Please enter your password:"),
QLineEdit::Password, QString::null, &makeConnection, this);
// allow null password entry in case its valid for the database
}
// Need to escape the password to allow for single quotes and backslashes
password.replace('\\', "\\\\");
password.replace('\'', "\\'");
connString += " password='" + password + "'";
QgsDataSourceURI uri;
uri.setConnection( settings.readEntry(key + "/host"),
settings.readEntry(key + "/port"),
database,
settings.readEntry(key + "/username"),
password );
QgsDebugMsg("Connection info: " + connString);
bool searchPublicOnly = settings.readBoolEntry(key + "/publicOnly");
bool searchGeometryColumnsOnly = settings.readBoolEntry(key + "/geometryColumnsOnly");
// Need to escape the password to allow for single quotes and backslashes
QgsDebugMsg("Connection info: " + uri.connInfo());
if (makeConnection)
{
m_connInfo = connString; //host + " " + database + " " + username + " " + password;
m_connInfo = uri.connInfo();
//qDebug(m_connInfo);
// Tidy up an existing connection if one exists.
if (pd != 0)

View File

@ -22,6 +22,9 @@
#include "qgsnewconnection.h"
#include "qgscontexthelp.h"
#include "qgsdatasourceuri.h"
#include "qgslogger.h"
extern "C"
{
#include <libpq-fe.h>
@ -31,38 +34,38 @@ QgsNewConnection::QgsNewConnection(QWidget *parent, const QString& connName, Qt:
{
setupUi(this);
if (!connName.isEmpty())
{
// populate the dialog with the information stored for the connection
// populate the fields with the stored setting parameters
QSettings settings;
{
// populate the dialog with the information stored for the connection
// populate the fields with the stored setting parameters
QSettings settings;
QString key = "/PostgreSQL/connections/" + connName;
txtHost->setText(settings.readEntry(key + "/host"));
txtDatabase->setText(settings.readEntry(key + "/database"));
QString port = settings.readEntry(key + "/port");
if(port.length() ==0){
port = "5432";
}
txtPort->setText(port);
txtUsername->setText(settings.readEntry(key + "/username"));
Qt::CheckState s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/publicOnly", false))
s = Qt::Unchecked;
cb_publicSchemaOnly->setCheckState(s);
s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/geometrycolumnsOnly", false))
s = Qt::Unchecked;
cb_geometryColumnsOnly->setCheckState(s);
// Ensure that cb_plublicSchemaOnly is set correctly
on_cb_geometryColumnsOnly_clicked();
if (settings.readEntry(key + "/save") == "true")
{
txtPassword->setText(settings.readEntry(key + "/password"));
chkStorePassword->setChecked(true);
}
txtName->setText(connName);
QString key = "/PostgreSQL/connections/" + connName;
txtHost->setText(settings.readEntry(key + "/host"));
txtDatabase->setText(settings.readEntry(key + "/database"));
QString port = settings.readEntry(key + "/port");
if(port.length() ==0){
port = "5432";
}
txtPort->setText(port);
txtUsername->setText(settings.readEntry(key + "/username"));
Qt::CheckState s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/publicOnly", false))
s = Qt::Unchecked;
cb_publicSchemaOnly->setCheckState(s);
s = Qt::Checked;
if ( ! settings.readBoolEntry(key + "/geometrycolumnsOnly", false))
s = Qt::Unchecked;
cb_geometryColumnsOnly->setCheckState(s);
// Ensure that cb_plublicSchemaOnly is set correctly
on_cb_geometryColumnsOnly_clicked();
if (settings.readEntry(key + "/save") == "true")
{
txtPassword->setText(settings.readEntry(key + "/password"));
chkStorePassword->setChecked(true);
}
txtName->setText(connName);
}
}
/** Autoconnected SLOTS **/
void QgsNewConnection::on_btnOk_clicked()
@ -96,21 +99,12 @@ QgsNewConnection::~QgsNewConnection()
}
void QgsNewConnection::testConnection()
{
// following line uses Qt SQL plugin - currently not used
// QSqlDatabase *testCon = QSqlDatabase::addDatabase("QPSQL7","testconnection");
QgsDataSourceURI uri;
uri.setConnection( txtHost->text(), txtPort->text(), txtDatabase->text(), txtUsername->text(), txtPassword->text() );
// Need to escape the password to allow for single quotes and backslashes
QString password = txtPassword->text();
password.replace('\\', "\\\\");
password.replace('\'', "\\'");
QgsLogger::debug( "PQconnectdb(" + uri.connInfo() + ");" );
QString connInfo =
"host=" + txtHost->text() +
" dbname=" + txtDatabase->text() +
" port=" + txtPort->text() +
" user=" + txtUsername->text() +
" password='" + password + "'";
PGconn *pd = PQconnectdb(connInfo.toLocal8Bit().data());
PGconn *pd = PQconnectdb( uri.connInfo().toLocal8Bit().data() );
// std::cout << pd->ErrorMessage();
if (PQstatus(pd) == CONNECTION_OK)
{

View File

@ -34,28 +34,21 @@ QgsPgQueryBuilder::QgsPgQueryBuilder(QgsDataSourceURI *uri,
setupUi(this);
// The query builder must make its own connection to the database when
// using this constructor
QString connInfo = QString("host=%1 dbname=%2 port=%3 user=%4 password=%5")
.arg(mUri->host)
.arg(mUri->database)
.arg(mUri->port)
.arg(mUri->username)
.arg(mUri->password);
#ifdef QGISDEBUG
std::cerr << "Attempting connect using: " << connInfo.toLocal8Bit().data() << std::endl;
#endif
QString connInfo = mUri->connInfo();
QgsDebugMsg("Attempting connect using: " + connInfo);
mPgConnection = PQconnectdb(connInfo.toLocal8Bit().data());
// check the connection status
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>"))
.arg(mUri->table)
.arg(mUri->table() )
.arg(PQdb(mPgConnection))
.arg(PQhost(mPgConnection))
.arg(PQuser(mPgConnection));
mOwnConnection = true; // we own this connection since we created it
// tell the DB that we want text encoded in UTF8
PQsetClientEncoding(mPgConnection, "UNICODE");
// and strip any quotation as this code does it's own quoting.
trimQuotation();
lblDataUri->setText(datasource);
populateFields();
@ -77,22 +70,12 @@ QgsPgQueryBuilder::QgsPgQueryBuilder(QString tableName, PGconn *con,
{
setupUi(this);
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>"))
.arg(tableName)
.arg(PQdb(mPgConnection))
.arg(PQhost(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);
populateFields();
@ -109,7 +92,7 @@ void QgsPgQueryBuilder::populateFields()
{
// Populate the field vector for this layer. The field vector contains
// 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()));
QgsLogger::debug("Query executed: " + sql);
if (PQresultStatus(result) == PGRES_TUPLES_OK)
@ -152,30 +135,14 @@ void QgsPgQueryBuilder::populateFields()
mFieldMap[fieldName] = QgsField(fieldName, type, fieldType);
lstFields->insertItem(fieldName);
}
}else
}
else
{
#ifdef QGISDEBUG
std::cerr << "Error fetching a row from " << mUri->table.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg( "Error fetching a row from " + mUri->table() );
}
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()
{
if (lstFields->currentText().isEmpty())
@ -183,7 +150,7 @@ void QgsPgQueryBuilder::on_btnSampleValues_clicked()
QString sql = "SELECT DISTINCT \"" + lstFields->currentText() + "\" " +
"FROM (SELECT \"" + lstFields->currentText() + "\" " +
"FROM \"" + mUri->schema + "\".\"" + mUri->table + "\" " +
"FROM " + mUri->quotedTablename() + " " +
"LIMIT 5000) AS foo " +
"ORDER BY \"" + lstFields->currentText() + "\" "+
"LIMIT 25";
@ -224,7 +191,7 @@ void QgsPgQueryBuilder::on_btnGetAllValues_clicked()
return;
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
lstValues->clear();
// determine the field type
@ -272,8 +239,8 @@ void QgsPgQueryBuilder::on_btnTest_clicked()
else
{
QString numRows;
QString sql = "select count(*) from \"" + mUri->schema + "\".\"" + mUri->table
+ "\" where " + txtSQL->text();
QString sql = "select count(*) from " + mUri->quotedTablename()
+ " where " + txtSQL->text();
PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));
if (PQresultStatus(result) == PGRES_TUPLES_OK)
{
@ -297,8 +264,7 @@ void QgsPgQueryBuilder::on_btnTest_clicked()
// XXX This should really throw an exception
long QgsPgQueryBuilder::countRecords(QString where)
{
QString sql = "select count(*) from \"" + mUri->schema + "\".\"" + mUri->table
+ "\" where " + where;
QString sql = "select count(*) from " + mUri->quotedTablename() + " where " + where;
long numRows;
PGresult *result = PQexec(mPgConnection, (const char *)(sql.utf8()));

View File

@ -119,11 +119,6 @@ class QgsPgQueryBuilder : public QDialog, private Ui::QgsPgQueryBuilderBase {
*/
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
* @return Number of records or -1 if an error was encountered
*/

View File

@ -18,6 +18,7 @@
/* $Id: qgsdatasourceuri.h 5839 2006-09-19 18:04:21Z wonder $ */
#include "qgsdatasourceuri.h"
#include "qgslogger.h"
#include <QStringList>
#include <QRegExp>
@ -29,150 +30,257 @@ QgsDataSourceURI::QgsDataSourceURI()
QgsDataSourceURI::QgsDataSourceURI(QString uri)
{
// URI looks like this:
// host=192.168.1.5 dbname=test port=5342 user=gsherman password=xxx table=tablename
// (optionally at the end there might be: sql=..... )
// TODO: improve parsing
// A little bit of backwards compability. At r6193 the schema/table
// names became fully quoted, but with the problem that earlier
// project files then didn't load. This bit of code puts in the
// quotes that are now required.
QString uriModified = uri;
int start = uriModified.indexOf("table=\"");
if (start == -1)
{
// Need to put in some "'s
start = uriModified.indexOf("table=");
uriModified.insert(start+6, '"');
int start_dot = uriModified.indexOf('.', start+7);
if (start_dot != -1)
{
uriModified.insert(start_dot, '"');
uriModified.insert(start_dot+2, '"');
}
// and one at the end
int end = uriModified.indexOf(' ',start);
if (end != -1)
uriModified.insert(end, '"');
}
// Strip the table and sql statement name off and store them
int sqlStart = uriModified.find(" sql");
int tableStart = uriModified.find("table=");
// set table name
table = uriModified.mid(tableStart + 6, sqlStart - tableStart -6);
int i = 0;
while( i<uri.length() )
{
skipBlanks(uri, i);
// set sql where clause
if(sqlStart > -1)
{
sql = uriModified.mid(sqlStart + 5);
if( uri[i] == '=' )
{
QgsDebugMsg("parameter name expected before =");
i++;
continue;
}
int start = i;
while( i<uri.length() && uri[i]!='=' && !uri[i].isSpace() )
i++;
QString pname = uri.mid(start, i-start);
skipBlanks(uri, i);
if( uri[i]!='=' ) {
QgsDebugMsg("= expected after parameter name");
return;
}
i++;
if( pname=="sql" ) {
// rest of line is a sql where clause
skipBlanks(uri, i);
mSql = uri.mid(i);
break;
} else {
QString pval = getValue(uri, i);
if( pname=="table" ) {
if( uri[i] == '.' ) {
i++;
mSchema = pval;
mTable = getValue(uri, i);
} else {
mSchema = "";
mTable = pval;
}
if( uri[i] == '(' ) {
i++;
int start = i;
QString col;
while( i<uri.length() && uri[i]!=')')
i++;
if( i==uri.length() ) {
QgsDebugMsg("closing parenthesis missing");
}
mGeometryColumn = uri.mid(start, i-start);
i++;
}
} else if( pname=="service" ) {
QgsDebugMsg("service keyword ignored");
} else if(pname=="user") {
mUsername = pval;
} else if(pname=="password") {
mPassword = pval;
} else if(pname=="connect_timeout") {
QgsDebugMsg("connection timeout ignored");
} else if(pname=="dbname") {
mDatabase = pval;
} else if(pname=="host") {
mHost = pval;
} else if(pname=="hostaddr") {
QgsDebugMsg("database host ip address ignored");
} else if(pname=="port") {
mPort = pval;
} else if(pname=="tty") {
QgsDebugMsg("backend debug tty ignored");
} else if(pname=="options") {
QgsDebugMsg("backend debug options ignored");
} else if(pname=="sslmode") {
QgsDebugMsg("sslmode ignored");
} else if(pname=="krbsrvname") {
QgsDebugMsg("kerberos server name ignored");
} else if(pname=="gsslib") {
QgsDebugMsg("gsslib ignored");
} else {
QgsDebugMsg( "invalid connection option \"" + pname + "\" ignored");
}
}
}
}
QString QgsDataSourceURI::username() const
{
return mUsername;
}
QString QgsDataSourceURI::schema() const
{
return mSchema;
}
QString QgsDataSourceURI::table() const
{
return mTable;
}
QString QgsDataSourceURI::sql() const
{
return mSql;
}
QString QgsDataSourceURI::geometryColumn() const
{
return mGeometryColumn;
}
void QgsDataSourceURI::setSql(QString sql)
{
mSql = sql;
}
void QgsDataSourceURI::skipBlanks(const QString &uri, int &i)
{
// skip space before value
while( i<uri.length() && uri[i].isSpace() )
i++;
}
QString QgsDataSourceURI::getValue(const QString &uri, int &i)
{
skipBlanks(uri, i);
// Get the parameter value
QString pval;
if( uri[i] == '\'' || uri[i]=='"' ) {
QChar delim = uri[i];
i++;
// value is quoted
for (;;)
{
if( i==uri.length() ) {
QgsDebugMsg("unterminated quoted string in connection info string");
return pval;
}
if( uri[i] == '\\') {
i++;
if( i==uri.length() )
continue;
} else if(uri[i]==delim) {
i++;
break;
}
pval += uri[i++];
}
} else {
// value is not quoted
while( i<uri.length() ) {
if( uri[i].isSpace() ) {
// end of value
break;
}
if( uri[i] == '\\' ) {
i++;
if( i==uri.length() )
break;
}
pval += uri[i++];
}
}
skipBlanks(uri, i);
return pval;
}
QString QgsDataSourceURI::connInfo() const
{
QString connInfo = "dbname="+mDatabase;
if( mHost != "" )
{
connInfo += " host=" + mHost;
if( mPort!="" )
connInfo += " port=" + mPort;
}
if( mUsername != "" )
{
connInfo += " user=" + mUsername;
if( mPassword != "" )
{
QString p = mPassword;
p.replace('\\', "\\\\");
p.replace('\'', "\\'");
connInfo += " password='"+p+"'";
}
}
return connInfo;
}
QString QgsDataSourceURI::uri() const
{
return connInfo()
+ QString(" table=\"%1\".\"%2\" (%3) sql=%4")
.arg(mSchema)
.arg(mTable)
.arg(mGeometryColumn)
.arg(mSql);
}
QString QgsDataSourceURI::quotedTablename() const
{
if(mSchema!="")
return QString("\"%1\".\"%2\"").arg(mSchema).arg(mTable);
else
{
sql = QString::null;
}
// calculate the schema if specified
// Pick up some stuff from the uriModified: basically two bits of text
// inside double quote marks, separated by a .
QRegExp reg("\"(.+)\"\\.\"(.+)\".+\\((.+)\\)");
reg.indexIn(table);
QStringList stuff = reg.capturedTexts();
schema = stuff[1];
table = stuff[2];
geometryColumn = stuff[3];
// set connection info
connInfo = uriModified.left(uriModified.find("table="));
// parse the connection info
QStringList conParts = QStringList::split(" ", connInfo);
QStringList parm = QStringList::split("=", conParts[0]);
if(parm.size() == 2)
{
host = parm[1];
}
parm = QStringList::split("=", conParts[1]);
if(parm.size() == 2)
{
database = parm[1];
}
parm = QStringList::split("=", conParts[2]);
if(parm.size() == 2)
{
port = parm[1];
}
parm = QStringList::split("=", conParts[3]);
if(parm.size() == 2)
{
username = parm[1];
}
// The password can have '=' and ' ' characters in it, so we can't
// use the split on '=' and ' ' technique - use indexOf()
// instead.
QString key="password='";
int i = connInfo.indexOf(key);
if (i != -1)
{
QString pass = connInfo.mid(i+key.length());
// Now walk through the string till we find a ' character, but
// need to allow for an escaped ' character (which will be the
// \' character pair).
int n = 0;
bool escaped = false;
while (n < pass.length() && (pass[n] != '\'' || escaped))
{
if (pass[n] == '\\')
escaped = true;
else
escaped = false;
n++;
}
// The -1 is to remove the trailing ' character
password = pass.left(n);
}
return QString("\"%1\"").arg(mTable);
}
QString QgsDataSourceURI::text() const
void QgsDataSourceURI::setConnection(const QString &host,
const QString &port,
const QString &database,
const QString &username,
const QString &password)
{
return QString("host=" + host +
" dbname=" + database +
" port=" + port +
" user=" + username +
" password='" + password +
"' table=" + schema + '.' + table +
" (" + geometryColumn + ")" +
" sql=" + sql);
}
void QgsDataSourceURI::setConnection(const QString& aHost,
const QString& aPort,
const QString& aDatabase,
const QString& aUsername,
const QString& aPassword)
{
host = aHost;
database = aDatabase;
port = aPort;
username = aUsername;
password = aPassword;
mHost = host;
mDatabase = database;
mPort = port;
mUsername = username;
mPassword = password;
}
void QgsDataSourceURI::setDataSource(const QString& aSchema,
const QString& aTable,
const QString& aGeometryColumn,
const QString& aSql)
void QgsDataSourceURI::setDataSource(const QString &schema,
const QString &table,
const QString &geometryColumn,
const QString &sql)
{
schema = aSchema;
table = aTable;
geometryColumn = aGeometryColumn;
sql = aSql;
mSchema = schema;
mTable = table;
mGeometryColumn = geometryColumn;
mSql = sql;
}

View File

@ -39,10 +39,16 @@ public:
//! constructor which parses input URI
QgsDataSourceURI(QString uri);
//! All in a single string
QString text() const;
//! return connection part of URI
QString connInfo() const;
//! return complete uri
QString uri() const;
//! quoted table name
QString quotedTablename() const;
//! Set all connection related members at once
void setConnection(const QString& aHost,
const QString& aPort,
@ -55,31 +61,39 @@ public:
const QString& aTable,
const QString& aGeometryColumn,
const QString& aSql = QString());
QString username() const;
QString schema() const;
QString table() const;
QString sql() const;
QString geometryColumn() const;
void setSql(QString sql);
private:
void skipBlanks(const QString &uri, int &i);
QString getValue(const QString &uri, int &i);
/* data */
//! host name
QString host;
QString mHost;
//! database name
QString database;
QString mDatabase;
//! port the database server listens on
QString port;
QString mPort;
//! schema
QString schema;
QString mSchema;
//! spatial table
QString table;
QString mTable;
//! geometry column
QString geometryColumn;
QString mGeometryColumn;
//! SQL where clause used to limit features returned from the layer
QString sql;
QString mSql;
//! username
QString username;
QString mUsername;
//! password
QString password;
//! whole connection info (host, db, port, name, pass)
QString connInfo;
QString mPassword;
};
#endif //QGSDATASOURCEURI_H

View File

@ -1616,8 +1616,7 @@ bool QgsVectorLayer::readXML_( QDomNode & layer_node )
// if the provider string isn't empty, then we successfully
// got the stored provider
}
else if ((mDataSource.find("host=") > -1) &&
(mDataSource.find("dbname=") > -1))
else if ( mDataSource.contains("dbname=") )
{
mProviderKey = "postgres";
}

View File

@ -28,6 +28,8 @@ email : sherman at mrcc.com
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsfield.h"
#include "qgsdatasourceuri.h"
#include "qgslogger.h"
#include <QMessageBox>
#include <QAction>
@ -96,45 +98,29 @@ void QgsPgGeoprocessing::buffer()
if (layer->type() != QgsMapLayer::RASTER &&
lyr->providerType() == "postgres") {
QString dataSource = lyr->source(); //qI->activeLayerSource();
QgsDataSourceURI uri( lyr->source() );
QgsDebugMsg("data source = " + uri.connInfo() );
// create the connection string
QString connInfo = dataSource.left(dataSource.find("table="));
#ifdef QGISDEBUG
std::cerr << "Data source = " << QString("Datasource:%1\n\nConnectionInfo:%2").arg(dataSource).arg(connInfo).toLocal8Bit().data() << std::endl;
#endif
// connect to the database and check the capabilities
PGconn *capTest = PQconnectdb((const char *) connInfo);
PGconn *capTest = PQconnectdb((const char *) uri.connInfo() );
if (PQstatus(capTest) == CONNECTION_OK) {
postgisVersion(capTest);
}
PQfinish(capTest);
if(geosAvailable){
// get the table name
QStringList connStrings = QStringList::split(" ", dataSource);
QStringList tables = connStrings.grep("table=");
QString table = tables[0];
QString tableName = table.mid(table.find("=") + 1);
// get the schema
QString schema = tableName.left(tableName.find("."));
// get the database name
QStringList dbnames = connStrings.grep("dbname=");
QString dbname = dbnames[0];
dbname = dbname.mid(dbname.find("=") + 1);
// get the user name
QStringList userNames = connStrings.grep("user=");
QString user = userNames[0];
user = user.mid(user.find("=") + 1);
// show dialog to fetch buffer distrance, new layer name, and option to
// add the new layer to the map
QgsDlgPgBuffer *bb = new QgsDlgPgBuffer(qI);
// set the label
QString lbl = tr("Buffer features in layer %1").arg(tableName);
QString lbl = tr("Buffer features in layer %1").arg( uri.table() );
bb->setBufferLabel(lbl);
// set a default output table name
bb->setBufferLayerName(tableName.mid(tableName.find(".") + 1) + "_buffer");
bb->setBufferLayerName( uri.table() + "_buffer");
QString tableName = uri.quotedTablename();
// set the fields on the dialog box drop-down
QgsVectorDataProvider *dp = dynamic_cast<QgsVectorDataProvider *>(lyr->getDataProvider());
QgsFieldMap flds = dp->fields();
@ -145,11 +131,11 @@ void QgsPgGeoprocessing::buffer()
}
}
// connect to the database
PGconn *conn = PQconnectdb((const char *) connInfo);
PGconn *conn = PQconnectdb((const char *) uri.connInfo() );
if (PQstatus(conn) == CONNECTION_OK) {
// populate the schema drop-down
QString schemaSql =
QString("select nspname from pg_namespace,pg_user where nspowner = usesysid and usename = '%1'").arg(user);
QString("select nspname from pg_namespace,pg_user where nspowner = usesysid and usename = '%1'").arg( uri.username() );
PGresult *schemas = PQexec(conn, (const char *) schemaSql);
if (PQresultStatus(schemas) == PGRES_TUPLES_OK) {
// add the schemas to the drop-down, otherwise just public (the
@ -162,11 +148,11 @@ void QgsPgGeoprocessing::buffer()
// query the geometry_columns table to get the srid and use it as default
QString sridSql =
QString("select srid,f_geometry_column from geometry_columns where f_table_schema='%1' and f_table_name='%2'")
.arg(schema)
.arg(tableName.mid(tableName.find(".") + 1));
#ifdef QGISDEBUG
std::cerr << "SRID SQL" << sridSql.toLocal8Bit().data() << std::endl;
#endif
.arg( uri.schema() )
.arg( uri.table() );
QgsDebugMsg("SRID SQL: " + sridSql);
QString geometryCol;
PGresult *sridq = PQexec(conn, (const char *) sridSql);
if (PQresultStatus(sridq) == PGRES_TUPLES_OK) {
@ -203,9 +189,8 @@ void QgsPgGeoprocessing::buffer()
sql = QString("set search_path = '%1','public'").arg(bb->schema());
result = PQexec(conn, (const char *) sql);
PQclear(result);
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("SQL: " + sql);
}
// first create the new table
@ -214,15 +199,14 @@ void QgsPgGeoprocessing::buffer()
.arg(bb->bufferLayerName())
.arg(objId)
.arg(objIdType);
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("SQL: " + sql);
result = PQexec(conn, (const char *) sql);
#ifdef QGISDEBUG
std::cerr << "Status from create table is " << PQresultStatus(result) << std::endl;
std::cerr << "Error message is " << PQresStatus(PQresultStatus(result)) << std::endl;
#endif
if (PQresultStatus(result) == PGRES_COMMAND_OK) {
QgsDebugMsg( QString("Status from create table is %1").arg( PQresultStatus(result) ) );
QgsDebugMsg( QString("Error message is %1").arg(PQresStatus(PQresultStatus(result))) );
if (PQresultStatus(result) == PGRES_COMMAND_OK)
{
PQclear(result);
// add the geometry column
//<db_name>, <table_name>, <column_name>, <srid>, <type>, <dimension>
@ -233,9 +217,8 @@ void QgsPgGeoprocessing::buffer()
.arg(bb->srid())
.arg("POLYGON")
.arg("2");
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("SQL: " + sql);
PGresult *geoCol = PQexec(conn, (const char *) sql);
if (PQresultStatus(geoCol) == PGRES_TUPLES_OK) {
@ -248,9 +231,9 @@ void QgsPgGeoprocessing::buffer()
sql = QString("alter table %1.%2 drop constraint \"enforce_geotype_shape\"")
.arg(bb->schema())
.arg(bb->bufferLayerName());
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg( "SQL: " + sql);
result = PQexec(conn, (const char *) sql);
if(PQresultStatus(result) == PGRES_COMMAND_OK)
{
@ -264,11 +247,11 @@ void QgsPgGeoprocessing::buffer()
if(version < "7.4.0"){
// modify the tableName
tableName = tableName.mid(tableName.find(".")+1);
tableName = uri.table();
}
#ifdef QGISDEBUG
std::cerr << "Table name for PG 7.3 is: " << tableName.mid(tableName.find(".")+1).toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("Table name for PG 7.3 is: " + uri.table() );
// if(PQresultStatus(geoCol) == PGRES_COMMAND_OK) {
// do the buffer and insert the features
if (objId == "objectid") {
@ -285,17 +268,14 @@ void QgsPgGeoprocessing::buffer()
.arg(geometryCol)
.arg(bb->bufferDistance().toDouble())
.arg(tableName);
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("SQL: " + sql);
}
result = PQexec(conn, (const char *) sql);
PQclear(result);
// }
#ifdef QGISDEBUG
std::cerr << sql.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("SQL: " + sql);
result = PQexec(conn, "end work");
PQclear(result);
result = PQexec(conn, "commit;vacuum");
@ -305,17 +285,15 @@ void QgsPgGeoprocessing::buffer()
// add new layer to the map
if (bb->addLayerToMap()) {
// create the connection string
QString newLayerSource = dataSource.left(dataSource.find("table="));
#ifdef QGISDEBUG
std::cerr << "newLayerSource: " << newLayerSource.toLocal8Bit().data() << std::endl;
#endif
QString newLayerSource = uri.connInfo();
QgsDebugMsg("newLayerSource: " + newLayerSource );
// add the schema.table and geometry column
/* newLayerSource += "table=" + bb->schema() + "." + bb->bufferLayerName()
+ " (" + bb->geometryColumn() + ")"; */
#ifdef QGISDEBUG
std::cerr << "newLayerSource: " << newLayerSource.toLocal8Bit().data() << std::endl;
std::cerr << "Adding new layer using\n\t" << newLayerSource.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("Adding new layer using " + newLayerSource);
// host=localhost dbname=gis_data user=gsherman password= table=public.alaska (the_geom)
// Using addVectorLayer requires that be add a table=xxxx to the layer path since
// addVectorLayer is generic for all supported layers
@ -335,18 +313,15 @@ void QgsPgGeoprocessing::buffer()
}
else
{
#ifdef QGISDEBUG
std::cerr << "Status from drop constraint is " << PQresultStatus(result) << std::endl;
std::cerr << "Error message is " << PQresStatus(PQresultStatus(result)) << std::endl;
#endif
QgsDebugMsg(QString("Status from drop constraint is %1").arg(PQresultStatus(result)) );
QgsDebugMsg(QString("Error message is %1").arg( PQresStatus(PQresultStatus(result))) );
}
}
else
{
#ifdef QGISDEBUG
std::cerr << "Status from add geometry column is " << PQresultStatus(geoCol) << std::endl;
std::cerr << "Error message is " << PQresStatus(PQresultStatus(geoCol)) << std::endl;
#endif
QgsDebugMsg(QString("Status from add geometry column is %1").arg(PQresultStatus(geoCol)) );
QgsDebugMsg(QString("Error message is %1").arg( PQresStatus(PQresultStatus(geoCol))) );
QMessageBox::critical(0, tr("Unable to add geometry column"),
QString(tr("Unable to add geometry column to the output table ") +
QString("%1-%2").arg(bb->bufferLayerName()).arg(PQerrorMessage(conn))));
@ -365,7 +340,9 @@ void QgsPgGeoprocessing::buffer()
QString err = tr("Error connecting to the database");
QMessageBox::critical(0, err, PQerrorMessage(conn));
}
}else{
}
else
{
QMessageBox::critical(0,tr("No GEOS support"),
tr("Buffer function requires GEOS support in PostGIS"));
}
@ -384,9 +361,9 @@ void QgsPgGeoprocessing::buffer()
QString QgsPgGeoprocessing::postgisVersion(PGconn *connection){
PGresult *result = PQexec(connection, "select postgis_version()");
postgisVersionInfo = PQgetvalue(result,0,0);
#ifdef QGISDEBUG
std::cerr << "PostGIS version info: " << postgisVersionInfo.toLocal8Bit().data() << std::endl;
#endif
QgsDebugMsg("PostGIS version info: " + postgisVersionInfo);
// assume no capabilities
geosAvailable = false;
gistAvailable = false;

View File

@ -2643,19 +2643,8 @@ void QgsGrassModuleGdalInput::updateQgisLayers()
{
// Construct OGR DSN
QgsDataSourceURI dsUri(provider->dataSourceUri());
uri = "PG:host=" + dsUri.host
+ " dbname=" + dsUri.database;
if ( dsUri.port.length() > 0 )
uri += " port=" + dsUri.port;
if ( dsUri.username.length() > 0 )
uri += " user=" + dsUri.username;
if ( dsUri.password.length() > 0 )
uri += " password=" + dsUri.password;
ogrLayer = dsUri.schema + "." + dsUri.table;
uri = "PG:" + dsUri.connInfo();
ogrLayer = dsUri.schema() + "." + dsUri.table();
}
else
{

View File

@ -80,20 +80,17 @@ const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
mUri = QgsDataSourceURI(uri);
/* populate members from the uri structure */
mSchemaName = mUri.schema;
mTableName = mUri.table;
geometryColumn = mUri.geometryColumn;
sqlWhereClause = mUri.sql;
mSchemaName = mUri.schema();
mTableName = mUri.table();
geometryColumn = mUri.geometryColumn();
sqlWhereClause = mUri.sql();
// Keep a schema qualified table name for convenience later on.
if (mSchemaName.length() > 0)
mSchemaTableName = "\"" + mSchemaName + "\".\"" + mTableName + "\"";
else
mSchemaTableName = "\"" + mTableName + "\"";
mSchemaTableName = mUri.quotedTablename();
QgsDebugMsg("Table name is " + mTableName);
QgsDebugMsg("SQL is " + sqlWhereClause);
QgsDebugMsg("Connection info is " + mUri.connInfo);
QgsDebugMsg("Connection info is " + mUri.connInfo() );
QgsDebugMsg("Geometry column is: " + geometryColumn);
QgsDebugMsg("Schema is: " + mSchemaName);
@ -103,7 +100,7 @@ const QString POSTGRES_DESCRIPTION = "PostgreSQL/PostGIS data provider";
//pLog.open((const char *)logFile);
//QgsDebugMsg("Opened log file for " + mTableName);
connection = connectDb( (const char *)mUri.connInfo );
connection = connectDb( (const char *)mUri.connInfo() );
if( connection==NULL ) {
valid = false;
return;
@ -2214,15 +2211,14 @@ void QgsPostgresProvider::setSubsetString(QString theSQL)
{
sqlWhereClause=theSQL;
// Update datasource uri too
mUri.sql=theSQL;
mUri.setSql(theSQL);
// Update yet another copy of the uri. Why are there 3 copies of the
// uri? Perhaps this needs some rationalisation.....
setDataSourceUri(mUri.text());
setDataSourceUri(mUri.connInfo());
// need to recalculate the number of features...
getFeatureCount();
calculateExtents();
}
long QgsPostgresProvider::getFeatureCount()
@ -2551,8 +2547,8 @@ bool QgsPostgresProvider::getGeometryDetails()
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
" end "
"from %2").arg(geometryColumn).arg(mSchemaTableName);
if(mUri.sql!="")
sql += " where " + mUri.sql;
if(mUri.sql()!="")
sql += " where " + mUri.sql();
result = executeDbCommand(connection, sql);