Skip to content

Commit 8d36542

Browse files
author
jef
committedDec 13, 2008
postgis table selection dialog:
- only ask for a password, when postgis needs one (fixes #1400) - don't complain about 'no accessible geometry tables', before checking for tables not listed in geometry_columns (fixes #1455) git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@9778 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 0a2c81c commit 8d36542

File tree

1 file changed

+136
-201
lines changed

1 file changed

+136
-201
lines changed
 

‎src/app/qgsdbsourceselect.cpp

Lines changed: 136 additions & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -357,22 +357,12 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
357357
// populate the table list
358358
QSettings settings;
359359

360-
bool makeConnection = true;
361360
QString key = "/PostgreSQL/connections/" + cmbConnections->currentText();
362361

363362
QString database = settings.value( key + "/database" ).toString();
364363
QString username = settings.value( key + "/username" ).toString();
365364
QString password = settings.value( key + "/password" ).toString();
366365

367-
if ( password.isEmpty() )
368-
{
369-
// get password from user
370-
makeConnection = false;
371-
password = QInputDialog::getText( this, tr( "Password for " ) + username,
372-
tr( "Please enter your password:" ),
373-
QLineEdit::Password, QString::null, &makeConnection );
374-
// allow null password entry in case its valid for the database
375-
}
376366

377367
QgsDataSourceURI uri;
378368
uri.setConnection( settings.value( key + "/host" ).toString(),
@@ -388,54 +378,79 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
388378

389379
QgsDebugMsg( "Connection info: " + uri.connectionInfo() );
390380

391-
if ( makeConnection )
381+
m_connectionInfo = uri.connectionInfo();
382+
//qDebug(m_connectionInfo);
383+
// Tidy up an existing connection if one exists.
384+
if ( pd != 0 )
385+
PQfinish( pd );
386+
387+
pd = PQconnectdb( m_connectionInfo.toLocal8Bit() ); // use what is set based on locale; after connecting, use Utf8
388+
389+
// if the connection needs a password ask for one
390+
if ( PQstatus( pd ) == CONNECTION_BAD && PQconnectionNeedsPassword( pd ) )
392391
{
393-
m_connectionInfo = uri.connectionInfo();
394-
//qDebug(m_connectionInfo);
395-
// Tidy up an existing connection if one exists.
396-
if ( pd != 0 )
392+
// get password from user
393+
bool makeConnection = false;
394+
password = QInputDialog::getText( this, tr( "Password for " ) + username,
395+
tr( "Please enter your password:" ),
396+
QLineEdit::Password, QString::null, &makeConnection );
397+
// allow null password entry in case its valid for the database
398+
if ( makeConnection )
399+
{
400+
uri.setConnection( settings.value( key + "/host" ).toString(),
401+
settings.value( key + "/port" ).toString(),
402+
database,
403+
settings.value( key + "/username" ).toString(),
404+
password );
405+
406+
m_connectionInfo = uri.connectionInfo();
397407
PQfinish( pd );
408+
pd = PQconnectdb( m_connectionInfo.toLocal8Bit() ); // use what is set based on locale; after connecting, use Utf8
409+
}
410+
}
398411

399-
pd = PQconnectdb( m_connectionInfo.toLocal8Bit() ); // use what is set based on locale; after connecting, use Utf8
400-
if ( PQstatus( pd ) == CONNECTION_OK )
401-
{
402-
//qDebug("Connection succeeded");
403-
// tell the DB that we want text encoded in UTF8
404-
PQsetClientEncoding( pd, QString( "UNICODE" ).toLocal8Bit() );
412+
if ( PQstatus( pd ) == CONNECTION_OK )
413+
{
414+
//qDebug("Connection succeeded");
415+
// tell the DB that we want text encoded in UTF8
416+
PQsetClientEncoding( pd, QString( "UNICODE" ).toLocal8Bit() );
405417

406-
// get the list of suitable tables and columns and populate the UI
407-
geomCol details;
418+
// get the list of suitable tables and columns and populate the UI
419+
geomCol details;
408420

409-
if ( getTableInfo( pd, searchGeometryColumnsOnly, searchPublicOnly ) )
421+
if ( getTableInfo( pd, searchGeometryColumnsOnly, searchPublicOnly ) )
422+
{
423+
// Start the thread that gets the geometry type for relations that
424+
// may take a long time to return
425+
if ( mColumnTypeThread != NULL )
410426
{
411-
// Start the thread that gets the geometry type for relations that
412-
// may take a long time to return
413-
if ( mColumnTypeThread != NULL )
414-
{
415-
connect( mColumnTypeThread, SIGNAL( setLayerType( QString, QString, QString, QString ) ),
416-
this, SLOT( setLayerType( QString, QString, QString, QString ) ) );
427+
connect( mColumnTypeThread, SIGNAL( setLayerType( QString, QString, QString, QString ) ),
428+
this, SLOT( setLayerType( QString, QString, QString, QString ) ) );
417429

418-
// Do it in a thread.
419-
mColumnTypeThread->start();
420-
}
430+
// Do it in a thread.
431+
mColumnTypeThread->start();
421432
}
422-
else
423-
{
424-
qDebug( "Unable to get list of spatially enabled tables from the database" );
425-
qDebug( PQerrorMessage( pd ) );
426-
}
427-
// BEGIN CHANGES ECOS
428-
if ( cmbConnections->count() > 0 )
429-
btnAdd->setEnabled( true );
430-
// END CHANGES ECOS
431433
}
432434
else
433435
{
434-
QMessageBox::warning( this, tr( "Connection failed" ),
435-
tr
436-
( "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.value( key + "/database" ).toString() ).arg( settings.value( key + "/host" ).toString() ).arg( "\n\n" ).arg( "\n\n" ).arg( "\n" ).arg( QString::fromUtf8( PQerrorMessage( pd ) ) ) );
436+
qDebug( "Unable to get list of spatially enabled tables from the database" );
437+
qDebug( PQerrorMessage( pd ) );
438438
}
439+
// BEGIN CHANGES ECOS
440+
if ( cmbConnections->count() > 0 )
441+
btnAdd->setEnabled( true );
442+
// END CHANGES ECOS
443+
}
444+
else
445+
{
446+
QMessageBox::warning( this, tr( "Connection failed" ),
447+
tr( "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" )
448+
.arg( settings.value( key + "/database" ).toString() )
449+
.arg( settings.value( key + "/host" ).toString() )
450+
.arg( "\n\n" )
451+
.arg( "\n\n" )
452+
.arg( "\n" )
453+
.arg( QString::fromUtf8( PQerrorMessage( pd ) ) ) );
439454
}
440455

441456
mTablesTreeView->sortByColumn( 1, Qt::AscendingOrder );
@@ -523,7 +538,7 @@ void QgsDbSourceSelect::addSearchGeometryColumn( const QString &schema, const QS
523538

524539
bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly )
525540
{
526-
bool ok = false;
541+
int n = 0;
527542
QApplication::setOverrideCursor( Qt::WaitCursor );
528543

529544
// The following query returns only tables that exist and the user has SELECT privilege on.
@@ -542,19 +557,12 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
542557
{
543558
QMessageBox::warning( this,
544559
tr( "Accessible tables could not be determined" ),
545-
QString( tr( "Database connection was successful, but the accessible tables could not be determined.\n\n"
546-
"The error message from the database was:\n%1\n" ) )
560+
tr( "Database connection was successful, but the accessible tables could not be determined.\n\n"
561+
"The error message from the database was:\n%1\n" )
547562
.arg( QString::fromUtf8( PQresultErrorMessage( result ) ) ) );
563+
n = -1;
548564
}
549-
else if ( PQntuples( result ) == 0 )
550-
{
551-
QMessageBox::warning( this, tr( "No accessible tables found" ),
552-
tr
553-
( "Database connection was successful, but no accessible tables were found.\n\n"
554-
"Please verify that you have SELECT privilege on a table carrying PostGIS\n"
555-
"geometry." ) );
556-
}
557-
else
565+
else if ( PQntuples( result ) > 0 )
558566
{
559567
for ( int idx = 0; idx < PQntuples( result ); idx++ )
560568
{
@@ -572,170 +580,97 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
572580
}
573581

574582
mTableModel.addTableEntry( type, schemaName, tableName, column, "" );
583+
n++;
575584
}
576585
}
577-
ok = true;
578586
}
587+
579588
PQclear( result );
580589

581590
//search for geometry columns in tables that are not in the geometry_columns metatable
582591
QApplication::restoreOverrideCursor();
583-
if ( searchGeometryColumnsOnly )
584-
{
585-
return ok;
586-
}
587-
588-
// Now have a look for geometry columns that aren't in the
589-
// geometry_columns table. This code is specific to postgresql,
590-
// but an equivalent query should be possible in other
591-
// databases.
592-
sql = "select pg_class.relname,pg_namespace.nspname,pg_attribute.attname,pg_class.relkind "
593-
"from pg_attribute, pg_class, pg_namespace "
594-
"where pg_namespace.oid = pg_class.relnamespace "
595-
"and pg_attribute.attrelid = pg_class.oid "
596-
"and ("
597-
"pg_attribute.atttypid = regtype('geometry')"
598-
" or "
599-
"pg_attribute.atttypid IN (select oid FROM pg_type WHERE typbasetype=regtype('geometry'))"
600-
") "
601-
"and has_schema_privilege(pg_namespace.nspname,'usage') "
602-
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') ";
603-
// user has select privilege
604-
if ( searchPublicOnly )
605-
sql += "and pg_namespace.nspname = 'public' ";
606-
607-
sql += "and not exists (select * from geometry_columns WHERE pg_namespace.nspname=f_table_schema AND pg_class.relname=f_table_name) "
608-
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
609-
610-
result = PQexec( pg, sql.toUtf8() );
611-
612-
for ( int i = 0; i < PQntuples( result ); i++ )
613-
{
614-
// Have the column name, schema name and the table name. The concept of a
615-
// catalog doesn't exist in postgresql so we ignore that, but we
616-
// do need to get the geometry type.
617-
618-
// Make the assumption that the geometry type for the first
619-
// row is the same as for all other rows.
620592

621-
QString table = QString::fromUtf8( PQgetvalue( result, i, 0 ) ); // relname
622-
QString schema = QString::fromUtf8( PQgetvalue( result, i, 1 ) ); // nspname
623-
QString column = QString::fromUtf8( PQgetvalue( result, i, 2 ) ); // attname
624-
QString relkind = QString::fromUtf8( PQgetvalue( result, i, 3 ) ); // relation kind
625-
626-
addSearchGeometryColumn( schema, table, column );
627-
//details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
628-
mTableModel.addTableEntry( "Waiting", schema, table, column, "" );
629-
}
630-
ok = true;
631-
632-
PQclear( result );
633-
return ok;
634-
}
593+
if ( !searchGeometryColumnsOnly )
594+
{
595+
// Now have a look for geometry columns that aren't in the
596+
// geometry_columns table. This code is specific to postgresql,
597+
// but an equivalent query should be possible in other
598+
// databases.
599+
sql = "select pg_class.relname,pg_namespace.nspname,pg_attribute.attname,pg_class.relkind "
600+
"from pg_attribute, pg_class, pg_namespace "
601+
"where pg_namespace.oid = pg_class.relnamespace "
602+
"and pg_attribute.attrelid = pg_class.oid "
603+
"and ("
604+
"pg_attribute.atttypid = regtype('geometry')"
605+
" or "
606+
"pg_attribute.atttypid IN (select oid FROM pg_type WHERE typbasetype=regtype('geometry'))"
607+
") "
608+
"and has_schema_privilege(pg_namespace.nspname,'usage') "
609+
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') ";
610+
// user has select privilege
611+
if ( searchPublicOnly )
612+
sql += "and pg_namespace.nspname = 'public' ";
613+
614+
if ( n > 0 )
615+
{
616+
sql += "and not exists (select * from geometry_columns WHERE pg_namespace.nspname=f_table_schema AND pg_class.relname=f_table_name) ";
617+
}
618+
else
619+
{
620+
n = 0;
621+
}
635622

636-
#if 0 // this function is never called - smizuno
637-
bool QgsDbSourceSelect::getGeometryColumnInfo( PGconn *pg,
638-
geomCol& details, bool searchGeometryColumnsOnly,
639-
bool searchPublicOnly )
640-
{
641-
bool ok = false;
623+
sql += "and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
642624

643-
QApplication::setOverrideCursor( Qt::waitCursor );
625+
result = PQexec( pg, sql.toUtf8() );
644626

645-
QString sql = "select * from geometry_columns";
646-
// where f_table_schema ='" + settings.value(key + "/database").toString() + "'";
647-
sql += " order by f_table_schema,f_table_name";
648-
//qDebug("Fetching tables using: " + sql);
649-
PGresult *result = PQexec( pg, sql.toUtf8() );
650-
if ( result )
651-
{
652-
QString msg;
653-
QTextStream( &msg ) << "Fetched " << PQntuples( result ) << " tables from database";
654-
//qDebug(msg);
655-
for ( int idx = 0; idx < PQntuples( result ); idx++ )
627+
if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
656628
{
657-
// Be a bit paranoid and check that the table actually
658-
// exists. This is not done as a subquery in the query above
659-
// because I can't get it to work correctly when there are tables
660-
// with capital letters in the name.
661-
662-
// Take care to deal with tables with the same name but in different schema.
663-
QString tableName = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, "f_table_name" ) ) );
664-
QString schemaName = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, "f_table_schema" ) ) );
665-
sql = "select oid from pg_class where relname = '" + tableName + "'";
666-
if ( schemaName.length() > 0 )
667-
sql += " and relnamespace = (select oid from pg_namespace where nspname = '" +
668-
schemaName + "')";
669-
670-
PGresult* exists = PQexec( pg, sql.toUtf8() );
671-
if ( PQntuples( exists ) == 1 )
629+
QMessageBox::warning( this,
630+
tr( "Accessible tables could not be determined" ),
631+
tr( "Database connection was successful, but the accessible tables could not be determined.\n\n"
632+
"The error message from the database was:\n%1\n" )
633+
.arg( QString::fromUtf8( PQresultErrorMessage( result ) ) ) );
634+
if ( n == 0 )
635+
n = -1;
636+
}
637+
else if ( PQntuples( result ) > 0 )
638+
{
639+
for ( int i = 0; i < PQntuples( result ); i++ )
672640
{
673-
QString column = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, "f_geometry_column" ) ) );
674-
QString type = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, "type" ) ) );
675-
676-
QString as = "";
677-
if ( type == "GEOMETRY" && !searchGeometryColumnsOnly )
678-
{
679-
addSearchGeometryColumn( schemaName, tableName, column );
680-
as = type = "WAITING";
681-
}
682-
683-
details.push_back( geomPair( fullDescription( schemaName, tableName, column, as ), type ) );
641+
// Have the column name, schema name and the table name. The concept of a
642+
// catalog doesn't exist in postgresql so we ignore that, but we
643+
// do need to get the geometry type.
644+
645+
// Make the assumption that the geometry type for the first
646+
// row is the same as for all other rows.
647+
648+
QString table = QString::fromUtf8( PQgetvalue( result, i, 0 ) ); // relname
649+
QString schema = QString::fromUtf8( PQgetvalue( result, i, 1 ) ); // nspname
650+
QString column = QString::fromUtf8( PQgetvalue( result, i, 2 ) ); // attname
651+
QString relkind = QString::fromUtf8( PQgetvalue( result, i, 3 ) ); // relation kind
652+
653+
addSearchGeometryColumn( schema, table, column );
654+
//details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
655+
mTableModel.addTableEntry( "Waiting", schema, table, column, "" );
656+
n++;
684657
}
685-
PQclear( exists );
686658
}
687-
ok = true;
688-
}
689-
PQclear( result );
690-
691-
QApplication::restoreOverrideCursor();
692-
693-
if ( searchGeometryColumnsOnly )
694-
return ok;
695659

696-
// Now have a look for geometry columns that aren't in the
697-
// geometry_columns table. This code is specific to postgresql,
698-
// but an equivalent query should be possible in other
699-
// databases.
700-
sql = "select pg_class.relname, pg_namespace.nspname, pg_attribute.attname, "
701-
"pg_class.relkind from "
702-
"pg_attribute, pg_class, pg_type, pg_namespace where pg_type.typname = 'geometry' and "
703-
"pg_attribute.atttypid = pg_type.oid and pg_attribute.attrelid = pg_class.oid ";
704-
705-
if ( searchPublicOnly )
706-
sql += "and pg_namespace.nspname = 'public' ";
707-
708-
sql += "and cast(pg_class.relname as character varying) not in "
709-
"(select f_table_name from geometry_columns) "
710-
"and pg_namespace.oid = pg_class.relnamespace "
711-
"and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
712-
713-
result = PQexec( pg, sql.toUtf8() );
660+
PQclear( result );
661+
}
714662

715-
for ( int i = 0; i < PQntuples( result ); i++ )
663+
if ( n == 0 )
716664
{
717-
// Have the column name, schema name and the table name. The concept of a
718-
// catalog doesn't exist in postgresql so we ignore that, but we
719-
// do need to get the geometry type.
720-
721-
// Make the assumption that the geometry type for the first
722-
// row is the same as for all other rows.
723-
724-
QString table = QString::fromUtf8( PQgetvalue( result, i, 0 ) ); // relname
725-
QString schema = QString::fromUtf8( PQgetvalue( result, i, 1 ) ); // nspname
726-
QString column = QString::fromUtf8( PQgetvalue( result, i, 2 ) ); // attname
727-
QString relkind = QString::fromUtf8( PQgetvalue( result, i, 3 ) ); // relation kind
728-
729-
addSearchGeometryColumn( schema, table, column );
730-
details.push_back( geomPair( fullDescription( schema, table, column, "WAITING" ), "WAITING" ) );
665+
QMessageBox::warning( this,
666+
tr( "No accessible tables found" ),
667+
tr( "Database connection was successful, but no accessible tables were found.\n\n"
668+
"Please verify that you have SELECT privilege on a table carrying PostGIS\n"
669+
"geometry." ) );
731670
}
732-
ok = true;
733-
734-
PQclear( result );
735671

736-
return ok;
672+
return n > 0;
737673
}
738-
#endif
739674

740675
void QgsDbSourceSelect::showHelp()
741676
{

0 commit comments

Comments
 (0)
Please sign in to comment.