31 |
31 |
#include <QMessageBox>
|
32 |
32 |
#include <QSettings>
|
33 |
33 |
#include <QTextStream>
|
34 |
|
#include <QTableWidgetItem>
|
35 |
34 |
#include <QHeaderView>
|
36 |
35 |
#include <QStringList>
|
37 |
36 |
|
38 |
|
#include <cassert>
|
39 |
|
#include <iostream>
|
40 |
|
|
41 |
37 |
#ifdef HAVE_PGCONFIG
|
42 |
38 |
#include <pg_config.h>
|
43 |
39 |
#endif
|
... | ... | |
57 |
53 |
mSearchColumnComboBox->addItem( tr( "Table" ) );
|
58 |
54 |
mSearchColumnComboBox->addItem( tr( "Type" ) );
|
59 |
55 |
mSearchColumnComboBox->addItem( tr( "Geometry column" ) );
|
|
56 |
mSearchColumnComboBox->addItem( tr( "Primary key column" ) );
|
60 |
57 |
mSearchColumnComboBox->addItem( tr( "Sql" ) );
|
61 |
58 |
|
62 |
59 |
mProxyModel.setParent( this );
|
... | ... | |
67 |
64 |
mTablesTreeView->setModel( &mProxyModel );
|
68 |
65 |
mTablesTreeView->setSortingEnabled( true );
|
69 |
66 |
|
|
67 |
mTablesTreeView->setEditTriggers( QAbstractItemView::CurrentChanged );
|
|
68 |
|
|
69 |
mTablesTreeView->setItemDelegateForColumn( QgsDbTableModel::dbtmPkCol, new QgsDbSourceSelectDelegate( this ) );
|
|
70 |
|
70 |
71 |
QSettings settings;
|
71 |
72 |
mTablesTreeView->setSelectionMode( settings.value( "/qgis/addPostgisDC", false ).toBool() ?
|
72 |
73 |
QAbstractItemView::ExtendedSelection :
|
... | ... | |
169 |
170 |
}
|
170 |
171 |
else if ( text == tr( "Schema" ) )
|
171 |
172 |
{
|
172 |
|
mProxyModel.setFilterKeyColumn( 0 );
|
|
173 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmSchema );
|
173 |
174 |
}
|
174 |
175 |
else if ( text == tr( "Table" ) )
|
175 |
176 |
{
|
176 |
|
mProxyModel.setFilterKeyColumn( 1 );
|
|
177 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmTable );
|
177 |
178 |
}
|
178 |
179 |
else if ( text == tr( "Type" ) )
|
179 |
180 |
{
|
180 |
|
mProxyModel.setFilterKeyColumn( 2 );
|
|
181 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmType );
|
181 |
182 |
}
|
182 |
183 |
else if ( text == tr( "Geometry column" ) )
|
183 |
184 |
{
|
184 |
|
mProxyModel.setFilterKeyColumn( 3 );
|
|
185 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmGeomCol );
|
185 |
186 |
}
|
|
187 |
else if ( text == tr( "Primay key column" ) )
|
|
188 |
{
|
|
189 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmPkCol );
|
|
190 |
}
|
186 |
191 |
else if ( text == tr( "Sql" ) )
|
187 |
192 |
{
|
188 |
|
mProxyModel.setFilterKeyColumn( 4 );
|
|
193 |
mProxyModel.setFilterKeyColumn( QgsDbTableModel::dbtmSql );
|
189 |
194 |
}
|
190 |
195 |
}
|
191 |
196 |
|
... | ... | |
199 |
204 |
QString type )
|
200 |
205 |
{
|
201 |
206 |
mTableModel.setGeometryTypesForTable( schema, table, column, type );
|
202 |
|
mTablesTreeView->sortByColumn( 1, Qt::AscendingOrder );
|
203 |
|
mTablesTreeView->sortByColumn( 0, Qt::AscendingOrder );
|
|
207 |
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmTable, Qt::AscendingOrder );
|
|
208 |
mTablesTreeView->sortByColumn( QgsDbTableModel::dbtmSchema, Qt::AscendingOrder );
|
204 |
209 |
}
|
205 |
210 |
|
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 );
|
216 |
|
}
|
217 |
|
|
218 |
211 |
QgsDbSourceSelect::~QgsDbSourceSelect()
|
219 |
212 |
{
|
220 |
213 |
PQfinish( pd );
|
221 |
214 |
}
|
|
215 |
|
222 |
216 |
void QgsDbSourceSelect::populateConnectionList()
|
223 |
217 |
{
|
224 |
218 |
QSettings settings;
|
... | ... | |
234 |
228 |
settings.endGroup();
|
235 |
229 |
setConnectionListPosition();
|
236 |
230 |
}
|
|
231 |
|
237 |
232 |
void QgsDbSourceSelect::addNewConnection()
|
238 |
233 |
{
|
239 |
234 |
QgsNewConnection *nc = new QgsNewConnection( this );
|
... | ... | |
243 |
238 |
populateConnectionList();
|
244 |
239 |
}
|
245 |
240 |
}
|
|
241 |
|
246 |
242 |
void QgsDbSourceSelect::editConnection()
|
247 |
243 |
{
|
248 |
244 |
QgsNewConnection *nc = new QgsNewConnection( this, cmbConnections->currentText() );
|
... | ... | |
278 |
274 |
setConnectionListPosition();
|
279 |
275 |
}
|
280 |
276 |
}
|
|
277 |
|
281 |
278 |
void QgsDbSourceSelect::addTables()
|
282 |
279 |
{
|
283 |
280 |
m_selectedTables.clear();
|
... | ... | |
310 |
307 |
|
311 |
308 |
if ( dbInfo[currentSchemaName][currentRow].size() == 0 )
|
312 |
309 |
{
|
313 |
|
dbInfo[currentSchemaName][currentRow].resize( 5 );
|
|
310 |
dbInfo[currentSchemaName][currentRow].resize( QgsDbTableModel::dbtmColumns );
|
314 |
311 |
}
|
315 |
312 |
|
316 |
313 |
dbInfo[currentSchemaName][currentRow][currentColumn] = currentItem->text();
|
317 |
314 |
}
|
318 |
315 |
|
319 |
316 |
//now traverse all the schemas and table infos
|
320 |
|
QString schemaName, tableName, geomColumnName, sql;
|
321 |
|
QString query;
|
322 |
|
|
323 |
317 |
QMap<QString, schemaInfo>::const_iterator schema_it = dbInfo.constBegin();
|
324 |
318 |
for ( ; schema_it != dbInfo.constEnd(); ++schema_it )
|
325 |
319 |
{
|
... | ... | |
327 |
321 |
schemaInfo::const_iterator entry_it = scheme.constBegin();
|
328 |
322 |
for ( ; entry_it != scheme.constEnd(); ++entry_it )
|
329 |
323 |
{
|
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 );
|
334 |
329 |
|
335 |
330 |
if ( geomColumnName.contains( " AS " ) )
|
336 |
331 |
{
|
337 |
332 |
int a = geomColumnName.indexOf( " AS " );
|
338 |
333 |
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
|
340 |
335 |
|
341 |
336 |
if ( !sql.isEmpty() )
|
342 |
337 |
{
|
... | ... | |
360 |
355 |
}
|
361 |
356 |
}
|
362 |
357 |
|
363 |
|
query = "\"" + schemaName + "\".\"" + tableName + "\" " + "(" + geomColumnName + ") sql=" + sql;
|
|
358 |
QString query;
|
|
359 |
if ( !pkColumnName.isEmpty() )
|
|
360 |
{
|
|
361 |
query += QString( "key=\"%1\" " ).arg( pkColumnName );
|
|
362 |
}
|
364 |
363 |
|
|
364 |
query += QString( "table=\"%1\".\"%2\" (%3) sql=%4" )
|
|
365 |
.arg( schemaName ).arg( tableName )
|
|
366 |
.arg( geomColumnName )
|
|
367 |
.arg( sql );
|
|
368 |
|
365 |
369 |
m_selectedTables.push_back( query );
|
366 |
370 |
}
|
367 |
371 |
}
|
... | ... | |
493 |
497 |
.arg( QString::fromUtf8( PQerrorMessage( pd ) ) ) );
|
494 |
498 |
}
|
495 |
499 |
|
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 );
|
498 |
502 |
|
499 |
503 |
//if we have only one schema item, expand it by default
|
500 |
504 |
int numTopLevelItems = mTableModel.invisibleRootItem()->rowCount();
|
... | ... | |
532 |
536 |
}
|
533 |
537 |
|
534 |
538 |
//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 );
|
537 |
541 |
if ( !schemaSibling.isValid() || !tableSibling.isValid() )
|
538 |
542 |
{
|
539 |
543 |
return;
|
... | ... | |
545 |
549 |
QgsDebugMsg( tableString );
|
546 |
550 |
|
547 |
551 |
QString currentSql;
|
548 |
|
QModelIndex sqlSibling = index.sibling( index.row(), 4 );
|
|
552 |
QModelIndex sqlSibling = index.sibling( index.row(), QgsDbTableModel::dbtmSql );
|
549 |
553 |
if ( sqlSibling.isValid() )
|
550 |
554 |
{
|
551 |
555 |
currentSql = mTableModel.itemFromIndex( mProxyModel.mapToSource( sqlSibling ) )->text();
|
... | ... | |
576 |
580 |
mColumnTypeThread->addGeometryColumn( schema, table, column );
|
577 |
581 |
}
|
578 |
582 |
|
|
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 |
|
579 |
610 |
bool QgsDbSourceSelect::getTableInfo( PGconn *pg, bool searchGeometryColumnsOnly, bool searchPublicOnly )
|
580 |
611 |
{
|
581 |
612 |
int n = 0;
|
... | ... | |
583 |
614 |
|
584 |
615 |
// The following query returns only tables that exist and the user has SELECT privilege on.
|
585 |
616 |
// 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";
|
592 |
634 |
|
593 |
635 |
PGresult *result = PQexec( pg, sql.toUtf8() );
|
594 |
636 |
if ( result )
|
... | ... | |
606 |
648 |
{
|
607 |
649 |
for ( int idx = 0; idx < PQntuples( result ); idx++ )
|
608 |
650 |
{
|
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() ) ) );
|
|
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 ) );
|
611 |
655 |
|
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() ) ) );
|
614 |
|
|
615 |
656 |
QString as = "";
|
616 |
657 |
if ( type == "GEOMETRY" && !searchGeometryColumnsOnly )
|
617 |
658 |
{
|
... | ... | |
619 |
660 |
as = type = "WAITING";
|
620 |
661 |
}
|
621 |
662 |
|
622 |
|
mTableModel.addTableEntry( type, schemaName, tableName, column, "" );
|
|
663 |
mTableModel.addTableEntry( type, schemaName, tableName, column, pkCandidates( pg, schemaName, tableName ), "" );
|
623 |
664 |
n++;
|
624 |
665 |
}
|
625 |
666 |
}
|
... | ... | |
636 |
677 |
// geometry_columns table. This code is specific to postgresql,
|
637 |
678 |
// but an equivalent query should be possible in other
|
638 |
679 |
// 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 ("
|
644 |
693 |
"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')";
|
650 |
698 |
// user has select privilege
|
651 |
699 |
if ( searchPublicOnly )
|
652 |
|
sql += "and pg_namespace.nspname = 'public' ";
|
|
700 |
sql += " and pg_namespace.nspname = 'public'";
|
653 |
701 |
|
654 |
702 |
if ( n > 0 )
|
655 |
703 |
{
|
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)";
|
657 |
705 |
}
|
658 |
706 |
else
|
659 |
707 |
{
|
660 |
708 |
n = 0;
|
661 |
709 |
}
|
662 |
710 |
|
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)
|
664 |
712 |
|
665 |
713 |
result = PQexec( pg, sql.toUtf8() );
|
666 |
714 |
|
... | ... | |
692 |
740 |
|
693 |
741 |
addSearchGeometryColumn( schema, table, column );
|
694 |
742 |
//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 ), "" );
|
696 |
744 |
n++;
|
697 |
745 |
}
|
698 |
746 |
}
|
... | ... | |
798 |
846 |
|
799 |
847 |
for ( uint i = 0; i < schemas.size(); i++ )
|
800 |
848 |
{
|
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] );
|
804 |
857 |
PGresult* gresult = PQexec( pd, query.toUtf8() );
|
805 |
858 |
QString type;
|
806 |
859 |
if ( PQresultStatus( gresult ) == PGRES_TUPLES_OK )
|