Skip to content

Commit 2ea7615

Browse files
author
jef
committed
- applied patch from Steven Mizuno from #964. Nice work. Thank you very much.
- better privilege handling (fixes #955) - better postgis i18n (unicode handling, identifier quotation) - password saving fixed - support for int8 type added - let provider capabilities follow table privileges (fixes #976) - use prepared statements for adding features (fixed #977) - remove connection pooling (fixes cursor problem) - clear attribute list on loadFields (fixes #984) - ignore bytea fields - handle transactions/error reporting better - some cleanups git-svn-id: http://svn.osgeo.org/qgis/trunk@8213 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent a0b7d73 commit 2ea7615

File tree

6 files changed

+692
-784
lines changed

6 files changed

+692
-784
lines changed

src/app/qgsdbsourceselect.cpp

Lines changed: 56 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ QString QgsDbSourceSelect::makeGeomQuery(QString schema,
181181
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
182182
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
183183
" end "
184-
"from \"%2\".\"%3\"").arg(column).arg(schema).arg(table);
184+
"from \"%2\".\"%3\"").arg("\""+column+"\"").arg(schema).arg(table);
185185
}
186186

187187
QgsDbSourceSelect::~QgsDbSourceSelect()
@@ -361,11 +361,11 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
361361
QString username = settings.readEntry(key + "/username");
362362
QString password = settings.readEntry(key + "/password");
363363

364-
if (password == QString::null)
364+
if ( password.isEmpty() )
365365
{
366366
// get password from user
367367
makeConnection = false;
368-
QString password = QInputDialog::getText(tr("Password for ") + username,
368+
password = QInputDialog::getText(tr("Password for ") + username,
369369
tr("Please enter your password:"),
370370
QLineEdit::Password, QString::null, &makeConnection, this);
371371
// allow null password entry in case its valid for the database
@@ -393,13 +393,13 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
393393
if (pd != 0)
394394
PQfinish(pd);
395395

396-
pd = PQconnectdb(m_connInfo.toLocal8Bit().data());
396+
pd = PQconnectdb(m_connInfo.toLocal8Bit()); // use what is set based on locale; after connecting, use Utf8
397397
// std::cout << pd->ErrorMessage();
398398
if (PQstatus(pd) == CONNECTION_OK)
399399
{
400400
//qDebug("Connection succeeded");
401401
// tell the DB that we want text encoded in UTF8
402-
PQsetClientEncoding(pd, "UNICODE");
402+
PQsetClientEncoding(pd, QString("UNICODE").toLocal8Bit());
403403

404404
// get the list of suitable tables and columns and populate the UI
405405
geomCol details;
@@ -434,7 +434,7 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
434434
QMessageBox::warning(this, tr("Connection failed"),
435435
tr
436436
("Connection to %1 on %2 failed. Either the database is down or your settings are incorrect.%3Check your username and password and try again.%4The database said:%5%6").
437-
arg(settings.readEntry(key + "/database")).arg(settings.readEntry(key + "/host")).arg("\n\n").arg("\n\n").arg("\n").arg(PQerrorMessage(pd)));
437+
arg(settings.readEntry(key + "/database")).arg(settings.readEntry(key + "/host")).arg("\n\n").arg("\n\n").arg("\n").arg(QString::fromLocal8Bit(PQerrorMessage(pd))));
438438
}
439439
}
440440

@@ -526,43 +526,33 @@ bool QgsDbSourceSelect::getTableInfo(PGconn *pg, bool searchGeometryColumnsOnly,
526526
bool ok = false;
527527
QApplication::setOverrideCursor(Qt::waitCursor);
528528

529-
QString sql = "select * from geometry_columns";
530-
sql += " order by f_table_schema,f_table_name";
531-
532-
PGresult *result = PQexec(pg, sql.toLocal8Bit().data());
529+
// The following query returns only tables that exist and the user has SELECT privilege on.
530+
// Can't use regclass here because table must exist, else error occurs.
531+
QString sql = "select * from geometry_columns,pg_class,pg_namespace "
532+
"where relname=f_table_name and f_table_schema=nspname "
533+
"and pg_namespace.oid = pg_class.relnamespace "
534+
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select')" // user has select privilege
535+
"order by f_table_schema,f_table_name";
536+
537+
PGresult *result = PQexec(pg, sql.toUtf8());
533538
if (result)
534539
{
535540
for (int idx = 0; idx < PQntuples(result); idx++)
536541
{
537-
// Be a bit paranoid and check that the table actually
538-
// exists. This is not done as a subquery in the query above
539-
// because I can't get it to work correctly when there are tables
540-
// with capital letters in the name.
542+
QString tableName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_table_name").toUtf8())));
543+
QString schemaName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_table_schema").toUtf8())));
541544

542-
// Take care to deal with tables with the same name but in different schema.
543-
QString tableName = PQgetvalue(result, idx, PQfnumber(result, "f_table_name"));
544-
QString schemaName = PQgetvalue(result, idx, PQfnumber(result, "f_table_schema"));
545-
sql = "select oid from pg_class where relname = '" + tableName + "'";
546-
if (schemaName.length() > 0)
547-
sql +=" and relnamespace = (select oid from pg_namespace where nspname = '" +
548-
schemaName + "')";
545+
QString column = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("f_geometry_column").toUtf8())));
546+
QString type = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, QString("type").toUtf8())));
549547

550-
PGresult* exists = PQexec(pg, sql.toLocal8Bit().data());
551-
if (PQntuples(exists) == 1)
548+
QString as = "";
549+
if(type=="GEOMETRY" && !searchGeometryColumnsOnly)
552550
{
553-
QString column = PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column"));
554-
QString type = PQgetvalue(result, idx, PQfnumber(result, "type"));
555-
556-
QString as = "";
557-
if(type=="GEOMETRY" && !searchGeometryColumnsOnly)
558-
{
559-
addSearchGeometryColumn(schemaName, tableName, column);
560-
as=type="WAITING";
561-
}
562-
563-
mTableModel.addTableEntry(type, schemaName, tableName, column, "");
551+
addSearchGeometryColumn(schemaName, tableName, column);
552+
as=type="WAITING";
564553
}
565-
PQclear(exists);
554+
555+
mTableModel.addTableEntry(type, schemaName, tableName, column, "");
566556
}
567557
ok = true;
568558
}
@@ -581,20 +571,21 @@ bool QgsDbSourceSelect::getTableInfo(PGconn *pg, bool searchGeometryColumnsOnly,
581571
// geometry_columns table. This code is specific to postgresql,
582572
// but an equivalent query should be possible in other
583573
// databases.
584-
sql = "select pg_class.relname, pg_namespace.nspname, pg_attribute.attname, "
585-
"pg_class.relkind from "
586-
"pg_attribute, pg_class, pg_type, pg_namespace where pg_type.typname = 'geometry' and "
587-
"pg_attribute.atttypid = pg_type.oid and pg_attribute.attrelid = pg_class.oid ";
588-
574+
sql = "select pg_class.relname, pg_namespace.nspname, pg_attribute.attname, pg_class.relkind "
575+
"from pg_attribute, pg_class, pg_namespace "
576+
"where pg_namespace.oid = pg_class.relnamespace "
577+
"and pg_attribute.atttypid = regtype('geometry') "
578+
"and pg_attribute.attrelid = pg_class.oid "
579+
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') ";
580+
// user has select privilege
589581
if (searchPublicOnly)
590582
sql += "and pg_namespace.nspname = 'public' ";
591583

592-
sql += "and cast(pg_class.relname as character varying) not in "
593-
"(select f_table_name from geometry_columns) "
594-
"and pg_namespace.oid = pg_class.relnamespace "
584+
sql += "and pg_namespace.nspname||'.'||pg_class.relname not in " // needs to be table and schema
585+
"(select f_table_schema||'.'||f_table_name from geometry_columns) "
595586
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
596587

597-
result = PQexec(pg, sql.toLocal8Bit().data());
588+
result = PQexec(pg, sql.toUtf8());
598589

599590
for (int i = 0; i < PQntuples(result); i++)
600591
{
@@ -605,10 +596,10 @@ bool QgsDbSourceSelect::getTableInfo(PGconn *pg, bool searchGeometryColumnsOnly,
605596
// Make the assumption that the geometry type for the first
606597
// row is the same as for all other rows.
607598

608-
QString table = PQgetvalue(result, i, 0); // relname
609-
QString schema = PQgetvalue(result, i, 1); // nspname
610-
QString column = PQgetvalue(result, i, 2); // attname
611-
QString relkind = PQgetvalue(result, i, 3); // relation kind
599+
QString table = QString::fromUtf8(PQgetvalue(result, i, 0)); // relname
600+
QString schema = QString::fromUtf8(PQgetvalue(result, i, 1)); // nspname
601+
QString column = QString::fromUtf8(PQgetvalue(result, i, 2)); // attname
602+
QString relkind = QString::fromUtf8(PQgetvalue(result, i, 3)); // relation kind
612603

613604
addSearchGeometryColumn(schema, table, column);
614605
//details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
@@ -620,6 +611,7 @@ bool QgsDbSourceSelect::getTableInfo(PGconn *pg, bool searchGeometryColumnsOnly,
620611
return ok;
621612
}
622613

614+
#if 0 // this function is never called - smizuno
623615
bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
624616
geomCol& details, bool searchGeometryColumnsOnly,
625617
bool searchPublicOnly)
@@ -632,7 +624,7 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
632624
// where f_table_schema ='" + settings.readEntry(key + "/database") + "'";
633625
sql += " order by f_table_schema,f_table_name";
634626
//qDebug("Fetching tables using: " + sql);
635-
PGresult *result = PQexec(pg, sql.toLocal8Bit().data());
627+
PGresult *result = PQexec(pg, sql.toUtf8());
636628
if (result)
637629
{
638630
QString msg;
@@ -646,18 +638,18 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
646638
// with capital letters in the name.
647639

648640
// Take care to deal with tables with the same name but in different schema.
649-
QString tableName = PQgetvalue(result, idx, PQfnumber(result, "f_table_name"));
650-
QString schemaName = PQgetvalue(result, idx, PQfnumber(result, "f_table_schema"));
641+
QString tableName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_table_name")));
642+
QString schemaName = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_table_schema")));
651643
sql = "select oid from pg_class where relname = '" + tableName + "'";
652644
if (schemaName.length() > 0)
653645
sql +=" and relnamespace = (select oid from pg_namespace where nspname = '" +
654646
schemaName + "')";
655647

656-
PGresult* exists = PQexec(pg, sql.toLocal8Bit().data());
648+
PGresult* exists = PQexec(pg, sql.toUtf8());
657649
if (PQntuples(exists) == 1)
658650
{
659-
QString column = PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column"));
660-
QString type = PQgetvalue(result, idx, PQfnumber(result, "type"));
651+
QString column = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "f_geometry_column")));
652+
QString type = QString::fromUtf8(PQgetvalue(result, idx, PQfnumber(result, "type")));
661653

662654
QString as = "";
663655
if(type=="GEOMETRY" && !searchGeometryColumnsOnly) {
@@ -695,7 +687,7 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
695687
"and pg_namespace.oid = pg_class.relnamespace "
696688
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
697689

698-
result = PQexec(pg, sql.toLocal8Bit().data());
690+
result = PQexec(pg, sql.toUtf8());
699691

700692
for (int i = 0; i < PQntuples(result); i++)
701693
{
@@ -706,10 +698,10 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
706698
// Make the assumption that the geometry type for the first
707699
// row is the same as for all other rows.
708700

709-
QString table = PQgetvalue(result, i, 0); // relname
710-
QString schema = PQgetvalue(result, i, 1); // nspname
711-
QString column = PQgetvalue(result, i, 2); // attname
712-
QString relkind = PQgetvalue(result, i, 3); // relation kind
701+
QString table = QString::fromUtf8(PQgetvalue(result, i, 0)); // relname
702+
QString schema = QString::fromUtf8(PQgetvalue(result, i, 1)); // nspname
703+
QString column = QString::fromUtf8(PQgetvalue(result, i, 2)); // attname
704+
QString relkind = QString::fromUtf8(PQgetvalue(result, i, 3)); // relation kind
713705

714706
addSearchGeometryColumn(schema, table, column);
715707
details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
@@ -720,6 +712,7 @@ bool QgsDbSourceSelect::getGeometryColumnInfo(PGconn *pg,
720712

721713
return ok;
722714
}
715+
#endif
723716

724717
void QgsDbSourceSelect::showHelp()
725718
{
@@ -800,23 +793,23 @@ void QgsGeomColumnTypeThread::getLayerTypes()
800793
{
801794
mStopped=false;
802795

803-
PGconn *pd = PQconnectdb(mConnInfo.toLocal8Bit().data());
796+
PGconn *pd = PQconnectdb(mConnInfo.toLocal8Bit());
804797
if (PQstatus(pd) == CONNECTION_OK)
805798
{
806-
PQsetClientEncoding(pd, "UNICODE");
799+
PQsetClientEncoding(pd, QString("UNICODE").toLocal8Bit());
807800

808801
for (uint i = 0; i<schemas.size(); i++)
809802
{
810803
QString query = QgsDbSourceSelect::makeGeomQuery(schemas[i],
811804
tables[i],
812805
columns[i]);
813-
PGresult* gresult = PQexec(pd, query.toLocal8Bit().data());
806+
PGresult* gresult = PQexec(pd, query.toUtf8());
814807
QString type;
815808
if (PQresultStatus(gresult) == PGRES_TUPLES_OK) {
816809
QStringList types;
817810

818811
for(int j=0; j<PQntuples(gresult); j++) {
819-
QString type = PQgetvalue(gresult, j, 0);
812+
QString type = QString::fromUtf8(PQgetvalue(gresult, j, 0));
820813
if(type!="")
821814
types += type;
822815
}

src/app/qgsnewconnection.cpp

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extern "C"
2929
{
3030
#include <libpq-fe.h>
3131
}
32+
3233
QgsNewConnection::QgsNewConnection(QWidget *parent, const QString& connName, Qt::WFlags fl)
3334
: QDialog(parent, fl)
3435
{
@@ -72,18 +73,22 @@ void QgsNewConnection::on_btnOk_clicked()
7273
{
7374
saveConnection();
7475
}
76+
7577
void QgsNewConnection::on_btnHelp_clicked()
7678
{
77-
helpInfo();
79+
helpInfo();
7880
}
81+
7982
void QgsNewConnection::on_btnConnect_clicked()
8083
{
8184
testConnection();
8285
}
86+
8387
void QgsNewConnection::on_btnCancel_clicked(){
8488
// cancel the dialog
8589
reject();
8690
}
91+
8792
void QgsNewConnection::on_cb_geometryColumnsOnly_clicked()
8893
{
8994
if (cb_geometryColumnsOnly->checkState() == Qt::Checked)
@@ -97,6 +102,7 @@ void QgsNewConnection::on_cb_geometryColumnsOnly_clicked()
97102
QgsNewConnection::~QgsNewConnection()
98103
{
99104
}
105+
100106
void QgsNewConnection::testConnection()
101107
{
102108
QgsDataSourceURI uri;
@@ -105,15 +111,15 @@ void QgsNewConnection::testConnection()
105111
QgsLogger::debug( "PQconnectdb(" + uri.connInfo() + ");" );
106112

107113
PGconn *pd = PQconnectdb( uri.connInfo().toLocal8Bit().data() );
108-
// std::cout << pd->ErrorMessage();
114+
// std::cout << pd->ErrorMessage();
109115
if (PQstatus(pd) == CONNECTION_OK)
110-
{
111-
// Database successfully opened; we can now issue SQL commands.
112-
QMessageBox::information(this, tr("Test connection"), tr("Connection to %1 was successful").arg(txtDatabase->text()));
116+
{
117+
// Database successfully opened; we can now issue SQL commands.
118+
QMessageBox::information(this, tr("Test connection"), tr("Connection to %1 was successful").arg(txtDatabase->text()));
113119
} else
114-
{
115-
QMessageBox::information(this, tr("Test connection"), tr("Connection failed - Check settings and try again.\n\nExtended error information:\n") + QString(PQerrorMessage(pd)) );
116-
}
120+
{
121+
QMessageBox::information(this, tr("Test connection"), tr("Connection failed - Check settings and try again.\n\nExtended error information:\n") + QString(PQerrorMessage(pd)) );
122+
}
117123
// free pg connection resources
118124
PQfinish(pd);
119125

@@ -130,36 +136,29 @@ void QgsNewConnection::saveConnection()
130136
settings.writeEntry(baseKey + "/database", txtDatabase->text());
131137
settings.writeEntry(baseKey + "/port", txtPort->text());
132138
settings.writeEntry(baseKey + "/username", txtUsername->text());
133-
settings.writeEntry(baseKey + "/password", txtPassword->text());
139+
settings.writeEntry(baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "");
134140
settings.writeEntry(baseKey + "/publicOnly", cb_publicSchemaOnly->isChecked());
135141
settings.writeEntry(baseKey + "/geometryColumnsOnly", cb_geometryColumnsOnly->isChecked());
136-
if (chkStorePassword->isChecked())
137-
{
138-
settings.writeEntry(baseKey + "/save", "true");
139-
} else
140-
{
141-
settings.writeEntry(baseKey + "/save", "false");
142-
}
142+
settings.writeEntry(baseKey + "/save", chkStorePassword->isChecked() ? "true" : "false");
143143
accept();
144144
}
145+
145146
void QgsNewConnection::helpInfo()
146147
{
147148
QgsContextHelp::run(context_id);
148149
}
149-
/* void QgsNewConnection::saveConnection()
150+
151+
#if 0
152+
void QgsNewConnection::saveConnection()
150153
{
151-
QSettings settings;
152-
QString baseKey = "/PostgreSQL/connections/";
153-
baseKey += txtName->text();
154-
settings.writeEntry(baseKey + "/host", txtHost->text());
155-
settings.writeEntry(baseKey + "/database", txtDatabase->text());
156-
157-
settings.writeEntry(baseKey + "/username", txtUsername->text());
158-
if (chkStorePassword->isChecked()) {
159-
settings.writeEntry(baseKey + "/password", txtPassword->text());
160-
} else{
161-
settings.writeEntry(baseKey + "/password", "");
162-
}
154+
QSettings settings;
155+
QString baseKey = "/PostgreSQL/connections/";
156+
baseKey += txtName->text();
157+
settings.writeEntry(baseKey + "/host", txtHost->text());
158+
settings.writeEntry(baseKey + "/database", txtDatabase->text());
163159

160+
settings.writeEntry(baseKey + "/username", txtUsername->text());
161+
settings.writeEntry(baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "");
164162
accept();
165-
} */
163+
}
164+
#endif

0 commit comments

Comments
 (0)