Skip to content

Commit 3209fa6

Browse files
author
jef
committed
[FEATURE] add selection of postgres primary key column (for views; apply #1855)
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@11479 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 934b69d commit 3209fa6

File tree

4 files changed

+183
-87
lines changed

4 files changed

+183
-87
lines changed

src/app/qgsdbsourceselect.cpp

+120-67
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,9 @@ email : sherman at mrcc.com
3131
#include <QMessageBox>
3232
#include <QSettings>
3333
#include <QTextStream>
34-
#include <QTableWidgetItem>
3534
#include <QHeaderView>
3635
#include <QStringList>
3736

38-
#include <cassert>
39-
#include <iostream>
40-
4137
#ifdef HAVE_PGCONFIG
4238
#include <pg_config.h>
4339
#endif
@@ -57,6 +53,7 @@ QgsDbSourceSelect::QgsDbSourceSelect( QWidget *parent, Qt::WFlags fl )
5753
mSearchColumnComboBox->addItem( tr( "Table" ) );
5854
mSearchColumnComboBox->addItem( tr( "Type" ) );
5955
mSearchColumnComboBox->addItem( tr( "Geometry column" ) );
56+
mSearchColumnComboBox->addItem( tr( "Primary key column" ) );
6057
mSearchColumnComboBox->addItem( tr( "Sql" ) );
6158

6259
mProxyModel.setParent( this );
@@ -67,6 +64,10 @@ QgsDbSourceSelect::QgsDbSourceSelect( QWidget *parent, Qt::WFlags fl )
6764
mTablesTreeView->setModel( &mProxyModel );
6865
mTablesTreeView->setSortingEnabled( true );
6966

67+
mTablesTreeView->setEditTriggers( QAbstractItemView::CurrentChanged );
68+
69+
mTablesTreeView->setItemDelegateForColumn( QgsDbTableModel::dbtmPkCol, new QgsDbSourceSelectDelegate( this ) );
70+
7071
QSettings settings;
7172
mTablesTreeView->setSelectionMode( settings.value( "/qgis/addPostgisDC", false ).toBool() ?
7273
QAbstractItemView::ExtendedSelection :
@@ -169,23 +170,27 @@ void QgsDbSourceSelect::on_mSearchColumnComboBox_currentIndexChanged( const QStr
169170
}
170171
else if ( text == tr( "Schema" ) )
171172
{
172-
mProxyModel.setFilterKeyColumn( 0 );
173+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmSchema );
173174
}
174175
else if ( text == tr( "Table" ) )
175176
{
176-
mProxyModel.setFilterKeyColumn( 1 );
177+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmTable );
177178
}
178179
else if ( text == tr( "Type" ) )
179180
{
180-
mProxyModel.setFilterKeyColumn( 2 );
181+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmType );
181182
}
182183
else if ( text == tr( "Geometry column" ) )
183184
{
184-
mProxyModel.setFilterKeyColumn( 3 );
185+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmGeomCol );
186+
}
187+
else if ( text == tr( "Primay key column" ) )
188+
{
189+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmPkCol );
185190
}
186191
else if ( text == tr( "Sql" ) )
187192
{
188-
mProxyModel.setFilterKeyColumn( 4 );
193+
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmSql );
189194
}
190195
}
191196

@@ -199,26 +204,15 @@ void QgsDbSourceSelect::setLayerType( QString schema,
199204
QString type )
200205
{
201206
mTableModel.setGeometryTypesForTable( schema, table, column, type );
202-
mTablesTreeView->sortByColumn( 1, Qt::AscendingOrder );
203-
mTablesTreeView->sortByColumn( 0, Qt::AscendingOrder );
204-
}
205-
206-
QString QgsDbSourceSelect::makeGeomQuery( QString schema,
207-
QString table, QString column )
208-
{
209-
return QString( "select distinct "
210-
"case"
211-
" when geometrytype(%1) IN ('POINT','MULTIPOINT') THEN 'POINT'"
212-
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
213-
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
214-
" end "
215-
"from \"%2\".\"%3\"" ).arg( "\"" + column + "\"" ).arg( schema ).arg( table );
207+
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmTable, Qt::AscendingOrder );
208+
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmSchema, Qt::AscendingOrder );
216209
}
217210

218211
QgsDbSourceSelect::~QgsDbSourceSelect()
219212
{
220213
PQfinish( pd );
221214
}
215+
222216
void QgsDbSourceSelect::populateConnectionList()
223217
{
224218
QSettings settings;
@@ -234,6 +228,7 @@ void QgsDbSourceSelect::populateConnectionList()
234228
settings.endGroup();
235229
setConnectionListPosition();
236230
}
231+
237232
void QgsDbSourceSelect::addNewConnection()
238233
{
239234
QgsNewConnection *nc = new QgsNewConnection( this );
@@ -243,6 +238,7 @@ void QgsDbSourceSelect::addNewConnection()
243238
populateConnectionList();
244239
}
245240
}
241+
246242
void QgsDbSourceSelect::editConnection()
247243
{
248244
QgsNewConnection *nc = new QgsNewConnection( this, cmbConnections->currentText() );
@@ -278,6 +274,7 @@ void QgsDbSourceSelect::deleteConnection()
278274
setConnectionListPosition();
279275
}
280276
}
277+
281278
void QgsDbSourceSelect::addTables()
282279
{
283280
m_selectedTables.clear();
@@ -310,33 +307,31 @@ void QgsDbSourceSelect::addTables()
310307

311308
if ( dbInfo[currentSchemaName][currentRow].size() == 0 )
312309
{
313-
dbInfo[currentSchemaName][currentRow].resize( 5 );
310+
dbInfo[currentSchemaName][currentRow].resize( QgsDbTableModel::dbtmColumns );
314311
}
315312

316313
dbInfo[currentSchemaName][currentRow][currentColumn] = currentItem->text();
317314
}
318315

319316
//now traverse all the schemas and table infos
320-
QString schemaName, tableName, geomColumnName, sql;
321-
QString query;
322-
323317
QMap<QString, schemaInfo>::const_iterator schema_it = dbInfo.constBegin();
324318
for ( ; schema_it != dbInfo.constEnd(); ++schema_it )
325319
{
326320
schemaInfo scheme = schema_it.value();
327321
schemaInfo::const_iterator entry_it = scheme.constBegin();
328322
for ( ; entry_it != scheme.constEnd(); ++entry_it )
329323
{
330-
schemaName = entry_it->at( 0 );
331-
tableName = entry_it->at( 1 );
332-
geomColumnName = entry_it->at( 3 );
333-
sql = entry_it->at( 4 );
324+
QString schemaName = entry_it->at( QgsDbTableModel::dbtmSchema );
325+
QString tableName = entry_it->at( QgsDbTableModel::dbtmTable );
326+
QString geomColumnName = entry_it->at( QgsDbTableModel::dbtmGeomCol );
327+
QString pkColumnName = entry_it->at( QgsDbTableModel::dbtmPkCol );
328+
QString sql = entry_it->at( QgsDbTableModel::dbtmSql );
334329

335330
if ( geomColumnName.contains( " AS " ) )
336331
{
337332
int a = geomColumnName.indexOf( " AS " );
338333
QString typeName = geomColumnName.mid( a + 4 ); //only the type name
339-
geomColumnName = geomColumnName.mid( 0, a ); //only the geom column name
334+
geomColumnName = geomColumnName.left( a ); //only the geom column name
340335

341336
if ( !sql.isEmpty() )
342337
{
@@ -360,7 +355,16 @@ void QgsDbSourceSelect::addTables()
360355
}
361356
}
362357

363-
query = "\"" + schemaName + "\".\"" + tableName + "\" " + "(" + geomColumnName + ") sql=" + sql;
358+
QString query;
359+
if ( !pkColumnName.isEmpty() )
360+
{
361+
query += QString( "key=\"%1\" " ).arg( pkColumnName );
362+
}
363+
364+
query += QString( "table=\"%1\".\"%2\" (%3) sql=%4" )
365+
.arg( schemaName ).arg( tableName )
366+
.arg( geomColumnName )
367+
.arg( sql );
364368

365369
m_selectedTables.push_back( query );
366370
}
@@ -493,8 +497,8 @@ void QgsDbSourceSelect::on_btnConnect_clicked()
493497
.arg( QString::fromUtf8( PQerrorMessage( pd ) ) ) );
494498
}
495499

496-
mTablesTreeView->sortByColumn( 1, Qt::AscendingOrder );
497-
mTablesTreeView->sortByColumn( 0, Qt::AscendingOrder );
500+
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmTable, Qt::AscendingOrder );
501+
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmSchema, Qt::AscendingOrder );
498502

499503
//if we have only one schema item, expand it by default
500504
int numTopLevelItems = mTableModel.invisibleRootItem()->rowCount();
@@ -532,8 +536,8 @@ void QgsDbSourceSelect::setSql( const QModelIndex& index )
532536
}
533537

534538
//create "Schema"."Table" and find out existing sql string
535-
QModelIndex schemaSibling = index.sibling( index.row(), 0 );
536-
QModelIndex tableSibling = index.sibling( index.row(), 1 );
539+
QModelIndex schemaSibling = index.sibling( index.row(), QgsDbTableModel::dbtmSchema );
540+
QModelIndex tableSibling = index.sibling( index.row(), QgsDbTableModel::dbtmTable );
537541
if ( !schemaSibling.isValid() || !tableSibling.isValid() )
538542
{
539543
return;
@@ -545,7 +549,7 @@ void QgsDbSourceSelect::setSql( const QModelIndex& index )
545549
QgsDebugMsg( tableString );
546550

547551
QString currentSql;
548-
QModelIndex sqlSibling = index.sibling( index.row(), 4 );
552+
QModelIndex sqlSibling = index.sibling( index.row(), QgsDbTableModel::dbtmSql );
549553
if ( sqlSibling.isValid() )
550554
{
551555
currentSql = mTableModel.itemFromIndex( mProxyModel.mapToSource( sqlSibling ) )->text();
@@ -576,19 +580,57 @@ void QgsDbSourceSelect::addSearchGeometryColumn( const QString &schema, const QS
576580
mColumnTypeThread->addGeometryColumn( schema, table, column );
577581
}
578582

583+
QStringList QgsDbSourceSelect::pkCandidates( PGconn *pg, QString schemaName, QString tableName )
584+
{
585+
QStringList cols;
586+
cols << QString::null;
587+
588+
QString sql = QString( "select attname from pg_attribute join pg_type on atttypid=pg_type.oid WHERE pg_type.typname='int4' AND attrelid=regclass('\"%1\".\"%2\"')" ).arg( schemaName ).arg( tableName );
589+
QgsDebugMsg( sql );
590+
PGresult *colRes = PQexec( pg, sql.toUtf8() );
591+
592+
if ( PQresultStatus( colRes ) == PGRES_TUPLES_OK )
593+
{
594+
for ( int i = 0; i < PQntuples( colRes ); i++ )
595+
{
596+
QgsDebugMsg( PQgetvalue( colRes, i, 0 ) );
597+
cols << QString::fromUtf8( PQgetvalue( colRes, i, 0 ) );
598+
}
599+
}
600+
else
601+
{
602+
QgsDebugMsg( QString( "SQL:%1\nresult:%2\nerror:%3\n" ).arg( sql ).arg( PQresultStatus( colRes ) ).arg( PQerrorMessage( pg ) ) );
603+
}
604+
605+
PQclear( colRes );
606+
607+
return cols;
608+
}
609+
579610
bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly )
580611
{
581612
int n = 0;
582613
QApplication::setOverrideCursor( Qt::WaitCursor );
583614

584615
// The following query returns only tables that exist and the user has SELECT privilege on.
585616
// Can't use regclass here because table must exist, else error occurs.
586-
QString sql = "select * from geometry_columns,pg_class,pg_namespace "
587-
"where relname=f_table_name and f_table_schema=nspname "
588-
"and pg_namespace.oid = pg_class.relnamespace "
589-
"and has_schema_privilege(pg_namespace.nspname,'usage') "
590-
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') " // user has select privilege
591-
"order by f_table_schema,f_table_name,f_geometry_column";
617+
QString sql = "select "
618+
"f_table_name,"
619+
"f_table_schema,"
620+
"f_geometry_column,"
621+
"type"
622+
" from "
623+
"geometry_columns,"
624+
"pg_class,"
625+
"pg_namespace"
626+
" where "
627+
"relname=f_table_name"
628+
" and f_table_schema=nspname"
629+
" and pg_namespace.oid=pg_class.relnamespace"
630+
" and has_schema_privilege(pg_namespace.nspname,'usage')"
631+
" and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select')" // user has select privilege
632+
" order by "
633+
"f_table_schema,f_table_name,f_geometry_column";
592634

593635
PGresult *result = PQexec( pg, sql.toUtf8() );
594636
if ( result )
@@ -606,11 +648,10 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
606648
{
607649
for ( int idx = 0; idx < PQntuples( result ); idx++ )
608650
{
609-
QString tableName = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, QString( "f_table_name" ).toUtf8() ) ) );
610-
QString schemaName = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, QString( "f_table_schema" ).toUtf8() ) ) );
611-
612-
QString column = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, QString( "f_geometry_column" ).toUtf8() ) ) );
613-
QString type = QString::fromUtf8( PQgetvalue( result, idx, PQfnumber( result, QString( "type" ).toUtf8() ) ) );
651+
QString tableName = QString::fromUtf8( PQgetvalue( result, idx, 0 ) );
652+
QString schemaName = QString::fromUtf8( PQgetvalue( result, idx, 1 ) );
653+
QString column = QString::fromUtf8( PQgetvalue( result, idx, 2 ) );
654+
QString type = QString::fromUtf8( PQgetvalue( result, idx, 3 ) );
614655

615656
QString as = "";
616657
if ( type == "GEOMETRY" && !searchGeometryColumnsOnly )
@@ -619,7 +660,7 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
619660
as = type = "WAITING";
620661
}
621662

622-
mTableModel.addTableEntry( type, schemaName, tableName, column, "" );
663+
mTableModel.addTableEntry( type, schemaName, tableName, column, pkCandidates( pg, schemaName, tableName ), "" );
623664
n++;
624665
}
625666
}
@@ -636,31 +677,38 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
636677
// geometry_columns table. This code is specific to postgresql,
637678
// but an equivalent query should be possible in other
638679
// databases.
639-
sql = "select pg_class.relname,pg_namespace.nspname,pg_attribute.attname,pg_class.relkind "
640-
"from pg_attribute, pg_class, pg_namespace "
641-
"where pg_namespace.oid = pg_class.relnamespace "
642-
"and pg_attribute.attrelid = pg_class.oid "
643-
"and ("
680+
sql = "select "
681+
"pg_class.relname,"
682+
"pg_namespace.nspname,"
683+
"pg_attribute.attname,"
684+
"pg_class.relkind"
685+
" from "
686+
"pg_attribute,"
687+
"pg_class,"
688+
"pg_namespace"
689+
" where "
690+
"pg_namespace.oid = pg_class.relnamespace"
691+
" and pg_attribute.attrelid = pg_class.oid "
692+
" and ("
644693
"pg_attribute.atttypid = regtype('geometry')"
645-
" or "
646-
"pg_attribute.atttypid IN (select oid FROM pg_type WHERE typbasetype=regtype('geometry'))"
647-
") "
648-
"and has_schema_privilege(pg_namespace.nspname,'usage') "
649-
"and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select') ";
694+
" or pg_attribute.atttypid IN (select oid FROM pg_type WHERE typbasetype=regtype('geometry'))"
695+
")"
696+
" and has_schema_privilege(pg_namespace.nspname,'usage')"
697+
" and has_table_privilege('\"'||pg_namespace.nspname||'\".\"'||pg_class.relname||'\"','select')";
650698
// user has select privilege
651699
if ( searchPublicOnly )
652-
sql += "and pg_namespace.nspname = 'public' ";
700+
sql += " and pg_namespace.nspname = 'public'";
653701

654702
if ( n > 0 )
655703
{
656-
sql += "and not exists (select * from geometry_columns WHERE pg_namespace.nspname=f_table_schema AND pg_class.relname=f_table_name) ";
704+
sql += " and not exists (select * from geometry_columns WHERE pg_namespace.nspname=f_table_schema AND pg_class.relname=f_table_name)";
657705
}
658706
else
659707
{
660708
n = 0;
661709
}
662710

663-
sql += "and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
711+
sql += " and pg_class.relkind in ('v', 'r')"; // only from views and relations (tables)
664712

665713
result = PQexec( pg, sql.toUtf8() );
666714

@@ -692,7 +740,7 @@ bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
692740

693741
addSearchGeometryColumn( schema, table, column );
694742
//details.push_back(geomPair(fullDescription(schema, table, column, "WAITING"), "WAITING"));
695-
mTableModel.addTableEntry( "Waiting", schema, table, column, "" );
743+
mTableModel.addTableEntry( "Waiting", schema, table, column, pkCandidates( pg, schema, table ), "" );
696744
n++;
697745
}
698746
}
@@ -798,9 +846,14 @@ void QgsGeomColumnTypeThread::getLayerTypes()
798846

799847
for ( uint i = 0; i < schemas.size(); i++ )
800848
{
801-
QString query = QgsDbSourceSelect::makeGeomQuery( schemas[i],
802-
tables[i],
803-
columns[i] );
849+
QString query = QString( "select distinct "
850+
"case"
851+
" when geometrytype(%1) IN ('POINT','MULTIPOINT') THEN 'POINT'"
852+
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
853+
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
854+
" end "
855+
"from "
856+
"\"%2\".\"%3\"" ).arg( "\"" + columns[i] + "\"" ).arg( schemas[i] ).arg( tables[i] );
804857
PGresult* gresult = PQexec( pd, query.toUtf8() );
805858
QString type;
806859
if ( PQresultStatus( gresult ) == PGRES_TUPLES_OK )

0 commit comments

Comments
 (0)