Skip to content

Commit 3f2fe7e

Browse files
author
jef
committed
[FEATURE] allow adding geometryless layers from postgres
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@14248 c8812cc2-4d05-0410-92ff-de0c093fc19c
1 parent 9945818 commit 3f2fe7e

File tree

7 files changed

+138
-36
lines changed

7 files changed

+138
-36
lines changed

src/app/postgres/qgspgnewconnection.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ QgsPgNewConnection::QgsPgNewConnection( QWidget *parent, const QString& connName
5858
txtPort->setText( port );
5959
cb_publicSchemaOnly->setChecked( settings.value( key + "/publicOnly", false ).toBool() );
6060
cb_geometryColumnsOnly->setChecked( settings.value( key + "/geometrycolumnsOnly", false ).toBool() );
61-
// Ensure that cb_plublicSchemaOnly is set correctly
61+
cb_allowGeometrylessTables->setChecked( settings.value( key + "/allowGeometrylessTables", true ).toBool() );
62+
// Ensure that cb_publicSchemaOnly is set correctly
6263
on_cb_geometryColumnsOnly_clicked();
6364

6465
cb_useEstimatedMetadata->setChecked( settings.value( key + "/estimatedMetadata", false ).toBool() );
@@ -125,6 +126,7 @@ void QgsPgNewConnection::accept()
125126
settings.setValue( baseKey + "/password", chkStorePassword->isChecked() ? txtPassword->text() : "" );
126127
settings.setValue( baseKey + "/publicOnly", cb_publicSchemaOnly->isChecked() );
127128
settings.setValue( baseKey + "/geometryColumnsOnly", cb_geometryColumnsOnly->isChecked() );
129+
settings.setValue( baseKey + "/allowGeometrylessTables", cb_allowGeometrylessTables->isChecked() );
128130
settings.setValue( baseKey + "/sslmode", cbxSSLmode->itemData( cbxSSLmode->currentIndex() ).toInt() );
129131
settings.setValue( baseKey + "/saveUsername", chkStoreUsername->isChecked() ? "true" : "false" );
130132
settings.setValue( baseKey + "/savePassword", chkStorePassword->isChecked() ? "true" : "false" );

src/app/postgres/qgspgsourceselect.cpp

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,9 +362,9 @@ QString QgsPgSourceSelect::layerURI( const QModelIndex &index )
362362
uri += QString( " estimatedmetadata=true" );
363363
}
364364

365-
uri += QString( " table=\"%1\".\"%2\" (%3) sql=%4" )
365+
uri += QString( " table=\"%1\".\"%2\"%3 sql=%4" )
366366
.arg( schemaName ).arg( tableName )
367-
.arg( geomColumnName )
367+
.arg( geomColumnName.isEmpty() ? QString() : QString( " (%1)" ).arg( geomColumnName ) )
368368
.arg( sql );
369369

370370
return uri;
@@ -429,6 +429,7 @@ void QgsPgSourceSelect::on_btnConnect_clicked()
429429

430430
bool searchPublicOnly = settings.value( key + "/publicOnly" ).toBool();
431431
bool searchGeometryColumnsOnly = settings.value( key + "/geometryColumnsOnly" ).toBool();
432+
bool allowGeometrylessTables = settings.value( key + "/allowGeometrylessTables", true ).toBool();
432433
mUseEstimatedMetadata = settings.value( key + "/estimatedMetadata" ).toBool();
433434
// Need to escape the password to allow for single quotes and backslashes
434435

@@ -481,7 +482,7 @@ void QgsPgSourceSelect::on_btnConnect_clicked()
481482
// get the list of suitable tables and columns and populate the UI
482483
geomCol details;
483484

484-
if ( getTableInfo( pd, searchGeometryColumnsOnly, searchPublicOnly ) )
485+
if ( getTableInfo( pd, searchGeometryColumnsOnly, searchPublicOnly, allowGeometrylessTables ) )
485486
{
486487
// Start the thread that gets the geometry type for relations that
487488
// may take a long time to return
@@ -604,7 +605,7 @@ QStringList QgsPgSourceSelect::pkCandidates( PGconn *pg, QString schemaName, QSt
604605
return cols;
605606
}
606607

607-
bool QgsPgSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly )
608+
bool QgsPgSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly, bool allowGeometrylessTables )
608609
{
609610
int nColumns = 0;
610611
int nGTables = 0;
@@ -797,6 +798,58 @@ bool QgsPgSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly
797798
result = 0;
798799
}
799800

801+
if ( allowGeometrylessTables )
802+
{
803+
QString sql = "select "
804+
"pg_class.relname"
805+
",pg_namespace.nspname"
806+
",pg_class.relkind"
807+
" from "
808+
" pg_class"
809+
",pg_namespace"
810+
" where "
811+
"pg_namespace.oid=pg_class.relnamespace"
812+
" and has_schema_privilege( pg_namespace.nspname, 'usage' )"
813+
" and has_table_privilege( '\"' || pg_namespace.nspname || '\".\"' || pg_class.relname || '\"', 'select' )"
814+
" and pg_class.relkind in( 'v', 'r' )";
815+
816+
// user has select privilege
817+
if ( searchPublicOnly )
818+
sql += " and pg_namespace.nspname = 'public'";
819+
820+
QgsDebugMsg( "sql: " + sql );
821+
822+
result = PQexec( pg, sql.toUtf8() );
823+
824+
if ( PQresultStatus( result ) != PGRES_TUPLES_OK )
825+
{
826+
QMessageBox::warning( this,
827+
tr( "Accessible tables could not be determined" ),
828+
tr( "Database connection was successful, but the accessible tables could not be determined.\n\n"
829+
"The error message from the database was:\n%1\n" )
830+
.arg( QString::fromUtf8( PQresultErrorMessage( result ) ) ) );
831+
if ( nColumns == 0 )
832+
nColumns = -1;
833+
}
834+
else if ( PQntuples( result ) > 0 )
835+
{
836+
for ( int i = 0; i < PQntuples( result ); i++ )
837+
{
838+
QString table = QString::fromUtf8( PQgetvalue( result, i, 0 ) ); // relname
839+
QString schema = QString::fromUtf8( PQgetvalue( result, i, 1 ) ); // nspname
840+
QString relkind = QString::fromUtf8( PQgetvalue( result, i, 2 ) ); // relation kind
841+
842+
QgsDebugMsg( QString( "%1.%2: %3" ).arg( schema ).arg( table ).arg( relkind ) );
843+
844+
mTableModel.addTableEntry( tr( "No geometry" ), schema, table, QString::null, relkind == "v" ? pkCandidates( pg, schema, table ) : QStringList(), "" );
845+
nColumns++;
846+
}
847+
}
848+
849+
PQclear( result );
850+
result = 0;
851+
}
852+
800853
if ( nColumns == 0 )
801854
{
802855
QMessageBox::warning( this,

src/app/postgres/qgspgsourceselect.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ class QgsPgSourceSelect : public QDialog, private Ui::QgsPgSourceSelectBase
155155
typedef QList<geomPair> geomCol;
156156

157157
/**Inserts information about the spatial tables into mTableModel*/
158-
bool getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly );
158+
bool getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly, bool allowGeometrylessTables );
159159

160160
/** get primary key candidates (all int4 columns) */
161161
QStringList pkCandidates( PGconn *pg, QString schemaName, QString viewName );

src/core/qgsdatasourceuri.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ QgsDataSourceURI::QgsDataSourceURI( QString uri ) : mSSLmode( SSLprefer ), mKeyC
103103

104104
i++;
105105
}
106+
else
107+
{
108+
mGeometryColumn = QString::null;
109+
}
106110
}
107111
else if ( pname == "key" )
108112
{
@@ -439,9 +443,9 @@ QString QgsDataSourceURI::uri() const
439443
theUri += QString( " estimatedmetadata=true" );
440444
}
441445

442-
theUri += QString( " table=%1 (%2) sql=%3" )
446+
theUri += QString( " table=%1%2 sql=%3" )
443447
.arg( quotedTablename() )
444-
.arg( mGeometryColumn )
448+
.arg( mGeometryColumn.isNull() ? QString() : QString( " (%1)" ).arg( mGeometryColumn ) )
445449
.arg( mSql );
446450

447451
return theUri;

src/core/qgsvectorlayer.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
124124
setCoordinateSystem();
125125

126126
QSettings settings;
127-
if ( settings.value( "/qgis/use_symbology_ng", false ).toBool() )
127+
if ( settings.value( "/qgis/use_symbology_ng", false ).toBool() && geometryType() != QGis::NoGeometry )
128128
{
129129
// using symbology-ng!
130130
setUsingRendererV2( true );
@@ -139,7 +139,7 @@ QgsVectorLayer::QgsVectorLayer( QString vectorLayerPath,
139139
}
140140

141141
// if the default style failed to load or was disabled use some very basic defaults
142-
if ( !defaultLoadedFlag )
142+
if ( !defaultLoadedFlag && geometryType() != QGis::NoGeometry )
143143
{
144144
// add single symbol renderer
145145
if ( mUsingRendererV2 )

src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ QgsPostgresProvider::QgsPostgresProvider( QString const & uri )
7272

7373
mUri = QgsDataSourceURI( uri );
7474

75-
/* populate members from the uri structure */
75+
// populate members from the uri structure
7676
mSchemaName = mUri.schema();
7777
mTableName = mUri.table();
7878
geometryColumn = mUri.geometryColumn();
@@ -390,6 +390,11 @@ bool QgsPostgresProvider::declareCursor(
390390
bool fetchGeometry,
391391
QString whereClause )
392392
{
393+
if ( fetchGeometry && geometryColumn.isNull() )
394+
{
395+
return false;
396+
}
397+
393398
try
394399
{
395400
QString query = QString( "select %1" ).arg( quotedIdentifier( primaryKey ) );
@@ -548,7 +553,7 @@ void QgsPostgresProvider::select( QgsAttributeList fetchAttributes, QgsRectangle
548553

549554
QString whereClause;
550555

551-
if ( !rect.isEmpty() )
556+
if ( !rect.isEmpty() && !geometryColumn.isNull() )
552557
{
553558
if ( isGeography )
554559
{
@@ -983,10 +988,16 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
983988
sql = QString( "SELECT "
984989
"has_table_privilege(%1,'DELETE'),"
985990
"has_any_column_privilege(%1,'UPDATE'),"
986-
"has_column_privilege(%1,%2,'UPDATE'),"
991+
"%2"
987992
"has_table_privilege(%1,'INSERT'),"
988993
"current_schema()" )
989-
.arg( quotedValue( mQuery ) ).arg( quotedValue( geometryColumn ) );
994+
.arg( quotedValue( mQuery ) )
995+
.arg( geometryColumn.isNull()
996+
? QString( "" )
997+
: QString( "has_column_privilege(%1,%2,'UPDATE')," )
998+
.arg( quotedValue( mQuery ) )
999+
.arg( quotedValue( geometryColumn ) )
1000+
);
9901001
}
9911002
else
9921003
{
@@ -2254,18 +2265,28 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
22542265
connectionRW->PQexecNR( "BEGIN" );
22552266

22562267
// Prepare the INSERT statement
2257-
QString insert = QString( "INSERT INTO %1(%2" )
2258-
.arg( mQuery )
2259-
.arg( quotedIdentifier( geometryColumn ) ),
2260-
values = QString( ") VALUES (GeomFromWKB($1%1,%2)" )
2261-
.arg( connectionRW->useWkbHex() ? "" : "::bytea" )
2262-
.arg( srid );
2268+
QString insert = QString( "INSERT INTO %1(" ).arg( mQuery );
2269+
QString values;
2270+
QString delim = ",";
2271+
2272+
if ( !geometryColumn.isNull() )
2273+
{
2274+
insert += quotedIdentifier( geometryColumn );
2275+
values = QString( ") VALUES (GeomFromWKB($1%1,%2)" )
2276+
.arg( connectionRW->useWkbHex() ? "" : "::bytea" )
2277+
.arg( srid );
2278+
delim = ",";
2279+
}
2280+
else
2281+
{
2282+
delim = "";
2283+
}
22632284

22642285
int offset;
22652286
if ( primaryKeyType != "tid" && primaryKeyType != "oid" )
22662287
{
2267-
insert += "," + quotedIdentifier( primaryKey );
2268-
values += ",$2";
2288+
insert += delim + quotedIdentifier( primaryKey );
2289+
values += delim + "$2";
22692290
offset = 3;
22702291
}
22712292
else
@@ -2306,7 +2327,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
23062327
break;
23072328
}
23082329

2309-
insert += "," + quotedIdentifier( fieldname );
2330+
insert += delim + quotedIdentifier( fieldname );
23102331

23112332
QString defVal = defaultValue( it.key() ).toString();
23122333

@@ -2316,44 +2337,46 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist )
23162337
{
23172338
if ( defVal.isNull() )
23182339
{
2319-
values += ",NULL";
2340+
values += delim + "NULL";
23202341
}
23212342
else
23222343
{
2323-
values += "," + defVal;
2344+
values += delim + defVal;
23242345
}
23252346
}
23262347
else if ( fit->typeName() == "geometry" )
23272348
{
2328-
values += QString( ",geomfromewkt(%1)" ).arg( quotedValue( it->toString() ) );
2349+
values += QString( "%1geomfromewkt(%2)" ).arg( delim ).arg( quotedValue( it->toString() ) );
23292350
}
23302351
else if ( fit->typeName() == "geography" )
23312352
{
2332-
values += QString( ",st_geographyfromewkt(%1)" ).arg( quotedValue( it->toString() ) );
2353+
values += QString( "%1st_geographyfromewkt(%2)" ).arg( delim ).arg( quotedValue( it->toString() ) );
23332354
}
23342355
else
23352356
{
2336-
values += "," + quotedValue( it->toString() );
2357+
values += delim + quotedValue( it->toString() );
23372358
}
23382359
}
23392360
else
23402361
{
23412362
// value is not unique => add parameter
23422363
if ( fit->typeName() == "geometry" )
23432364
{
2344-
values += QString( ",geomfromewkt($%1)" ).arg( defaultValues.size() + offset );
2365+
values += QString( "%1geomfromewkt($%2)" ).arg( delim ).arg( defaultValues.size() + offset );
23452366
}
23462367
else if ( fit->typeName() == "geography" )
23472368
{
2348-
values += QString( ",st_geographyfromewkt($%1)" ).arg( defaultValues.size() + offset );
2369+
values += QString( "%1st_geographyfromewkt($%2)" ).arg( delim ).arg( defaultValues.size() + offset );
23492370
}
23502371
else
23512372
{
2352-
values += QString( ",$%1" ).arg( defaultValues.size() + offset );
2373+
values += QString( "%1$%2" ).arg( delim ).arg( defaultValues.size() + offset );
23532374
}
23542375
defaultValues.append( defVal );
23552376
fieldId.append( it.key() );
23562377
}
2378+
2379+
delim = ",";
23572380
}
23582381

23592382
insert += values + ")";
@@ -2656,7 +2679,7 @@ bool QgsPostgresProvider::changeGeometryValues( QgsGeometryMap & geometry_map )
26562679
{
26572680
QgsDebugMsg( "entering." );
26582681

2659-
if ( isQuery )
2682+
if ( isQuery || geometryColumn.isNull() )
26602683
return false;
26612684

26622685
if ( !connectRW() )
@@ -2811,6 +2834,9 @@ long QgsPostgresProvider::featureCount() const
28112834

28122835
QgsRectangle QgsPostgresProvider::extent()
28132836
{
2837+
if ( geometryColumn.isNull() )
2838+
return QgsRectangle();
2839+
28142840
if ( isGeography )
28152841
return QgsRectangle( -180.0, -90.0, 180.0, 90.0 );
28162842

@@ -2846,7 +2872,7 @@ QgsRectangle QgsPostgresProvider::extent()
28462872
// dateline extent() returns -180 to 180 (which appears right), but
28472873
// estimated_extent() returns eastern bound of data (>-180) and
28482874
// 180 degrees.
2849-
if ( !ext.startsWith( "-180 ") && ext.contains( ",180 " ) )
2875+
if ( !ext.startsWith( "-180 " ) && ext.contains( ",180 " ) )
28502876
{
28512877
ext.clear();
28522878
}
@@ -2974,6 +3000,13 @@ bool QgsPostgresProvider::deduceEndian()
29743000

29753001
bool QgsPostgresProvider::getGeometryDetails()
29763002
{
3003+
if ( geometryColumn.isNull() )
3004+
{
3005+
geomType = QGis::WKBNoGeometry;
3006+
valid = true;
3007+
return true;
3008+
}
3009+
29773010
QString fType( "" );
29783011
srid = "";
29793012
valid = false;

src/ui/qgspgnewconnectionbase.ui

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>323</width>
10-
<height>384</height>
9+
<width>352</width>
10+
<height>413</height>
1111
</rect>
1212
</property>
1313
<property name="sizePolicy">
@@ -228,7 +228,7 @@
228228
</item>
229229
</layout>
230230
</item>
231-
<item row="4" column="0">
231+
<item row="5" column="0">
232232
<widget class="QCheckBox" name="cb_useEstimatedMetadata">
233233
<property name="toolTip">
234234
<string>Use estimated table statistics for the layer metadata.</string>
@@ -249,6 +249,16 @@
249249
</property>
250250
</widget>
251251
</item>
252+
<item row="4" column="0">
253+
<widget class="QCheckBox" name="cb_allowGeometrylessTables">
254+
<property name="text">
255+
<string>Allow geometryless tables</string>
256+
</property>
257+
<property name="checked">
258+
<bool>true</bool>
259+
</property>
260+
</widget>
261+
</item>
252262
</layout>
253263
</widget>
254264
</item>

0 commit comments

Comments
 (0)