a) applied the patch suggested in ticket #3139

b) fixed the SourceSelect dialog so to avoid
   showing RasterLite-1 related tables


git-svn-id: http://svn.osgeo.org/qgis/trunk@14435 c8812cc2-4d05-0410-92ff-de0c093fc19c
This commit is contained in:
esseffe 2010-10-26 08:58:16 +00:00
parent 752bad8d76
commit 510d4259bb
4 changed files with 365 additions and 53 deletions

View File

@ -507,6 +507,8 @@ bool QgsSpatiaLiteSourceSelect::getTableInfo( sqlite3 * handle )
{
for ( i = 1; i <= rows; i++ )
{
if ( isRasterlite1Datasource( handle, results[( i * columns ) + 0] ) )
continue;
QString tableName = QString::fromUtf8( results[( i * columns ) + 0] );
QString column = QString::fromUtf8( results[( i * columns ) + 1] );
QString type = results[( i * columns ) + 2];
@ -698,6 +700,52 @@ bool QgsSpatiaLiteSourceSelect::checkVirtsGeometryColumns( sqlite3 * handle )
return exists;
}
bool QgsSpatiaLiteSourceSelect::isRasterlite1Datasource (sqlite3 * handle, const char *table)
{
// testing for RasterLite-1 datasources
int ret;
int i;
char **results;
int rows;
int columns;
bool exists = false;
int len;
char table_raster[4192];
char sql[4192];
strcpy ( table_raster, table );
len = strlen( table_raster );
if (strlen( table_raster ) < 9)
return false;
if (strcmp( table_raster + len - 9, "_metadata" ) != 0)
return false;
// ok, possible candidate
strcpy( table_raster + len - 9, "_rasters" );
// checking if the related "_RASTERS table exists
sprintf( sql, "SELECT name FROM sqlite_master WHERE type = 'table' AND name = '%s'", table_raster );
ret = sqlite3_get_table( handle, sql, &results, &rows, &columns, NULL );
if ( ret != SQLITE_OK )
return false;
if ( rows < 1 )
;
else
{
for ( i = 1; i <= rows; i++ )
{
if ( results[( i * columns ) + 0] != NULL )
{
const char *name = results[( i * columns ) + 0];
if ( name )
exists = true;
}
}
}
sqlite3_free_table( results );
return exists;
}
bool QgsSpatiaLiteSourceSelect::isDeclaredHidden( sqlite3 * handle, QString table, QString geom )
{
int ret;

View File

@ -117,6 +117,9 @@ class QgsSpatiaLiteSourceSelect: public QDialog, private Ui::QgsSpatiaLiteSource
/**Checks if this layer has been declared HIDDEN*/
bool isDeclaredHidden( sqlite3 * handle, QString table, QString geom );
/**Checks if this layer is a RasterLite-1 datasource*/
bool isRasterlite1Datasource( sqlite3 * handle, const char * table );
/**cleaning well-formatted SQL strings*/
QString quotedValue( QString value ) const;

View File

@ -52,6 +52,8 @@ QgsSpatiaLiteProvider::QgsSpatiaLiteProvider( QString const &uri )
mGeometryColumn = anUri.geometryColumn();
mSqlitePath = anUri.database();
mSubsetString = anUri.sql();
mPrimaryKey = anUri.keyColumn();
mQuery = mTableName;
// trying to open the SQLite DB
spatialite_init( 0 );
@ -131,6 +133,7 @@ void QgsSpatiaLiteProvider::loadFields()
{
int ret;
int i;
sqlite3_stmt *stmt = NULL;
char **results;
int rows;
int columns;
@ -138,58 +141,129 @@ void QgsSpatiaLiteProvider::loadFields()
QString pkName;
int pkCount = 0;
int fldNo = 0;
QString sql;
attributeFields.clear();
mPrimaryKey.clear();
QString sql = QString( "PRAGMA table_info(\"%1\")" ).arg( mTableName );
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK )
goto error;
if ( rows < 1 )
;
else
if ( !isQuery )
{
for ( i = 1; i <= rows; i++ )
mPrimaryKey.clear();
sql = QString( "PRAGMA table_info(%1)" ).arg( quotedIdentifier( mTableName ) );
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK )
goto error;
if ( rows < 1 )
;
else
{
QString name = QString::fromUtf8( results[( i * columns ) + 1] );
const char *type = results[( i * columns ) + 2];
QString pk = results[( i * columns ) + 5];
if ( pk.toInt() != 0 )
for ( i = 1; i <= rows; i++ )
{
// found a Primary Key column
pkCount++;
pkName = name;
}
if ( name != mGeometryColumn )
{
// for sure any SQLite value can be represented as SQLITE_TEXT
QVariant::Type fieldType = QVariant::String;
// making some assumptions in order to guess a more realistic type
if ( strcasecmp( type, "int" ) == 0 ||
strcasecmp( type, "integer" ) == 0 ||
strcasecmp( type, "bigint" ) == 0 ||
strcasecmp( type, "smallint" ) == 0 ||
strcasecmp( type, "tinyint" ) == 0 ||
strcasecmp( type, "boolean" ) == 0 )
QString name = QString::fromUtf8( results[( i * columns ) + 1] );
const char *type = results[( i * columns ) + 2];
QString pk = results[( i * columns ) + 5];
if ( pk.toInt() != 0 )
{
fieldType = QVariant::Int;
}
else if ( strcasecmp( type, "real" ) == 0 ||
strcasecmp( type, "double" ) == 0 ||
strcasecmp( type, "double precision" ) == 0 || strcasecmp( type, "float" ) == 0 )
{
fieldType = QVariant::Double;
// found a Primary Key column
pkCount++;
pkName = name;
}
attributeFields.insert( fldNo++, QgsField( name, fieldType, type, 0, 0, "" ) );
if ( name != mGeometryColumn )
{
// for sure any SQLite value can be represented as SQLITE_TEXT
QVariant::Type fieldType = QVariant::String;
// making some assumptions in order to guess a more realistic type
if ( strcasecmp( type, "int" ) == 0 ||
strcasecmp( type, "integer" ) == 0 ||
strcasecmp( type, "bigint" ) == 0 ||
strcasecmp( type, "smallint" ) == 0 ||
strcasecmp( type, "tinyint" ) == 0 ||
strcasecmp( type, "boolean" ) == 0 )
{
fieldType = QVariant::Int;
}
else if ( strcasecmp( type, "real" ) == 0 ||
strcasecmp( type, "double" ) == 0 ||
strcasecmp( type, "double precision" ) == 0 || strcasecmp( type, "float" ) == 0 )
{
fieldType = QVariant::Double;
}
attributeFields.insert( fldNo++, QgsField( name, fieldType, type, 0, 0, "" ) );
}
}
}
sqlite3_free_table( results );
}
sqlite3_free_table( results );
else
{
sql = QString( "select * from %1 limit 1" ).arg( mQuery );
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
{
// some error occurred
QgsDebugMsg( QString( "SQLite error: %1\n\nSQL: %2" )
.arg( sql )
.arg( QString::fromUtf8( sqlite3_errmsg( sqliteHandle ) ) ) );
return;
}
ret = sqlite3_step( stmt );
if ( ret == SQLITE_DONE )
{
// there are no rows to fetch
sqlite3_finalize( stmt );
return;
}
if ( ret == SQLITE_ROW )
{
// one valid row has been fetched from the result set
columns = sqlite3_column_count( stmt );
for ( i = 0; i < columns; i++ )
{
QString name = QString::fromUtf8( sqlite3_column_name( stmt, i ) );
const char *type = sqlite3_column_decltype( stmt, i );
if ( type == NULL )
type = "TEXT";
if ( name != mPrimaryKey )
{
pkCount++;
pkName = name;
}
if ( name != mGeometryColumn )
{
// for sure any SQLite value can be represented as SQLITE_TEXT
QVariant::Type fieldType = QVariant::String;
// making some assumptions in order to guess a more realistic type
if ( strcasecmp( type, "int" ) == 0 ||
strcasecmp( type, "integer" ) == 0 ||
strcasecmp( type, "bigint" ) == 0 ||
strcasecmp( type, "smallint" ) == 0 ||
strcasecmp( type, "tinyint" ) == 0 ||
strcasecmp( type, "boolean" ) == 0 )
{
fieldType = QVariant::Int;
}
else if ( strcasecmp( type, "real" ) == 0 ||
strcasecmp( type, "double" ) == 0 ||
strcasecmp( type, "double precision" ) == 0 || strcasecmp( type, "float" ) == 0 )
{
fieldType = QVariant::Double;
}
attributeFields.insert( fldNo++, QgsField( name, fieldType, type, 0, 0, "" ) );
}
}
}
sqlite3_finalize( stmt );
}
if ( pkCount == 1 )
{
@ -221,7 +295,9 @@ bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bo
feature.setValid( false );
QString sql = "SELECT ROWID";
QString primaryKey = !isQuery ? "ROWID" : quotedIdentifier( mPrimaryKey );
QString sql = QString( "SELECT %1" ).arg( primaryKey );
for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
{
const QgsField & fld = field( *it );
@ -232,7 +308,10 @@ bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bo
{
sql += QString( ", AsBinary(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
}
sql += QString( " FROM %1 WHERE ROWID = %2" ).arg( quotedIdentifier( mTableName ) ).arg( featureId );
sql += QString( " FROM %1 WHERE %2 = %3" )
.arg( mQuery )
.arg( primaryKey )
.arg( featureId );
if ( sqlite3_prepare_v2( sqliteHandle, sql.toUtf8().constData(), -1, &stmt, NULL ) != SQLITE_OK )
{
@ -267,7 +346,7 @@ bool QgsSpatiaLiteProvider::featureAtId( int featureId, QgsFeature & feature, bo
{
if ( ic == 0 )
{
// first column always contains the ROWID
// first column always contains the ROWID (or the primary key)
feature.setFeatureId( sqlite3_column_int( stmt, ic ) );
}
else
@ -391,7 +470,7 @@ bool QgsSpatiaLiteProvider::nextFeature( QgsFeature & feature )
{
if ( ic == 0 )
{
// first column always contains the ROWID
// first column always contains the ROWID (or the primary key)
feature.setFeatureId( sqlite3_column_int( sqliteStatement, ic ) );
}
else
@ -522,7 +601,9 @@ void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectang
sqliteStatement = NULL;
}
QString sql = "SELECT ROWID";
QString primaryKey = !isQuery ? "ROWID" : quotedIdentifier( mPrimaryKey );
QString sql = QString( "SELECT %1" ).arg( primaryKey );
for ( QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it )
{
const QgsField & fld = field( *it );
@ -533,7 +614,7 @@ void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectang
{
sql += QString( ", AsBinary(%1)" ).arg( quotedIdentifier( mGeometryColumn ) );
}
sql += QString( " FROM %1" ).arg( quotedIdentifier( mTableName ) );
sql += QString( " FROM %1" ).arg( mQuery );
QString whereClause;
@ -569,7 +650,10 @@ void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectang
mbrFilter += QString( "ymin <= %1 AND " ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
mbrFilter += QString( "ymax >= %1" ).arg( QString::number( rect.yMinimum(), 'f', 6 ) );
QString idxName = QString( "idx_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
whereClause += QString( "ROWID IN (SELECT pkid FROM %1 WHERE %2)" ).arg( quotedIdentifier( idxName ) ).arg( mbrFilter );
whereClause += QString( "%1 IN (SELECT pkid FROM %2 WHERE %3)" )
.arg( quotedIdentifier( primaryKey ) )
.arg( quotedIdentifier( idxName ) )
.arg( mbrFilter );
}
else if ( spatialIndexMbrCache )
{
@ -579,7 +663,10 @@ void QgsSpatiaLiteProvider::select( QgsAttributeList fetchAttributes, QgsRectang
arg( QString::number( rect.yMinimum(), 'f', 6 ) ).
arg( QString::number( rect.xMaximum(), 'f', 6 ) ).arg( QString::number( rect.yMaximum(), 'f', 6 ) );
QString idxName = QString( "cache_%1_%2" ).arg( mIndexTable ).arg( mIndexGeometry );
whereClause += QString( "ROWID IN (SELECT rowid FROM %1 WHERE mbr = FilterMbrIntersects(%2))" ).arg( quotedIdentifier( idxName ) ).arg( mbr );
whereClause += QString( "%1 IN (SELECT rowid FROM %2 WHERE mbr = FilterMbrIntersects(%3))" )
.arg( quotedIdentifier( primaryKey ) )
.arg( quotedIdentifier( idxName ) )
.arg( mbr );
}
else
{
@ -711,7 +798,7 @@ QVariant QgsSpatiaLiteProvider::minimumValue( int index )
// get the field name
const QgsField & fld = field( index );
QString sql = QString( "SELECT Min(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
QString sql = QString( "SELECT Min(%1) FROM %2" ).arg( quotedIdentifier( fld.name() ) ).arg( mQuery );
if ( !mSubsetString.isEmpty() )
{
@ -766,7 +853,7 @@ QVariant QgsSpatiaLiteProvider::maximumValue( int index )
// get the field name
const QgsField & fld = field( index );
QString sql = QString( "SELECT Max(\"%1\") FROM \"%2\"" ).arg( fld.name() ).arg( mTableName );
QString sql = QString( "SELECT Max(%1) FROM %2" ).arg( quotedIdentifier( fld.name() ) ).arg( mQuery );
if ( !mSubsetString.isEmpty() )
{
@ -819,7 +906,7 @@ void QgsSpatiaLiteProvider::uniqueValues( int index, QList < QVariant > &uniqueV
// get the field name
const QgsField & fld = field( index );
sql = QString( "SELECT DISTINCT \"%1\" FROM \"%2\" ORDER BY \"%1\"" ).arg( fld.name() ).arg( mTableName );
sql = QString( "SELECT DISTINCT %1 FROM %2 ORDER BY %1" ).arg( quotedIdentifier( fld.name() ) ).arg( mQuery );
if ( !mSubsetString.isEmpty() )
{
@ -1511,6 +1598,7 @@ bool QgsSpatiaLiteProvider::checkLayerType()
mTableBased = false;
mViewBased = false;
mVShapeBased = false;
isQuery = false;
// checking if this one is a Table-based layer
QString sql = QString( "SELECT read_only FROM geometry_columns "
@ -1594,6 +1682,49 @@ bool QgsSpatiaLiteProvider::checkLayerType()
}
sqlite3_free_table( results );
// checking if this one is a select query
if ( mQuery.startsWith( "(select", Qt::CaseInsensitive ) &&
mQuery.endsWith( ")" ) )
{
// get a new alias for the subquery
int index = 0;
QString alias;
QRegExp regex;
do
{
alias = QString( "subQuery_%1" ).arg( QString::number( index++ ) );
QString pattern = QString( "(\\\"?)%1\\1" ).arg( QRegExp::escape( alias ) );
regex.setPattern( pattern );
regex.setCaseSensitivity( Qt::CaseInsensitive );
}
while ( mQuery.contains( regex ) );
// convert the custom query into a subquery
mQuery = QString( "%1 as %2" )
.arg( mQuery )
.arg( quotedIdentifier( alias ) );
sql = QString( "SELECT 0 FROM %1 LIMIT 1" ).arg( mQuery );
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret == SQLITE_OK && rows == 1 )
{
isQuery = true;
mReadOnly = true;
count++;
}
if ( errMsg )
{
QgsDebugMsg( QString( "sqlite error %1 [%2]" ).arg( sql ).arg( errMsg ) );
sqlite3_free( errMsg );
errMsg = 0;
}
sqlite3_free_table( results );
}
else
{
mQuery = quotedIdentifier( mTableName );
}
// checking for validity
return count == 1;
}
@ -1607,6 +1738,8 @@ bool QgsSpatiaLiteProvider::getGeometryDetails()
ret = getViewGeometryDetails();
if ( mVShapeBased )
ret = getVShapeGeometryDetails();
if ( isQuery )
ret = getQueryGeometryDetails();
return ret;
}
@ -1845,6 +1978,122 @@ error:
return false;
}
bool QgsSpatiaLiteProvider::getQueryGeometryDetails()
{
int ret;
int i;
char **results;
int rows;
int columns;
char *errMsg = NULL;
QString fType( "" );
QString xSrid( "" );
// get stuff from the relevant column instead. This may (will?)
// fail if there is no data in the relevant table.
QString sql = QString( "select srid(%1), geometrytype(%1) from %2" )
.arg( quotedIdentifier( mGeometryColumn ) )
.arg( mQuery );
//it is possible that the where clause restricts the feature type
if ( !mSubsetString.isEmpty() )
{
sql += " WHERE " + mSubsetString;
}
sql += " limit 1";
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK )
goto error;
if ( rows < 1 )
;
else
{
for ( i = 1; i <= rows; i++ )
{
xSrid = results[( i * columns ) + 0];
fType = results[( i * columns ) + 1];
}
}
sqlite3_free_table( results );
if ( !xSrid.isEmpty() && !fType.isEmpty() )
{
if ( fType == "GEOMETRY" )
{
// check to see if there is a unique geometry type
sql = QString( "select distinct "
"case"
" when geometrytype(%1) IN ('POINT','MULTIPOINT') THEN 'POINT'"
" when geometrytype(%1) IN ('LINESTRING','MULTILINESTRING') THEN 'LINESTRING'"
" when geometrytype(%1) IN ('POLYGON','MULTIPOLYGON') THEN 'POLYGON'"
" end "
"from %2" )
.arg( quotedIdentifier( mGeometryColumn ) )
.arg( mQuery );
if ( !mSubsetString.isEmpty() )
sql += " where " + mSubsetString;
ret = sqlite3_get_table( sqliteHandle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK )
goto error;
if ( rows != 1 )
;
else
{
for ( i = 1; i <= rows; i++ )
{
fType = results[( 1 * columns ) + 0];
}
}
sqlite3_free_table( results );
}
if ( fType == "POINT" )
{
geomType = QGis::WKBPoint;
}
else if ( fType == "MULTIPOINT" )
{
geomType = QGis::WKBMultiPoint;
}
else if ( fType == "LINESTRING" )
{
geomType = QGis::WKBLineString;
}
else if ( fType == "MULTILINESTRING" )
{
geomType = QGis::WKBMultiLineString;
}
else if ( fType == "POLYGON" )
{
geomType = QGis::WKBPolygon;
}
else if ( fType == "MULTIPOLYGON" )
{
geomType = QGis::WKBMultiPolygon;
}
mSrid = xSrid.toInt();
}
if ( geomType == QGis::WKBUnknown || mSrid < 0 )
goto error;
return getSridDetails();
error:
// unexpected error
if ( errMsg != NULL )
{
QgsDebugMsg( QString( "SQL error: %1\n\n%2" ).arg( sql ).arg( errMsg ? QString::fromUtf8( errMsg ) : "unknown cause" ) );
sqlite3_free( errMsg );
}
return false;
}
bool QgsSpatiaLiteProvider::getSridDetails()
{
int ret;
@ -1891,8 +2140,10 @@ bool QgsSpatiaLiteProvider::getTableSummary()
int columns;
char *errMsg = NULL;
QString sql = QString( "SELECT Min(MbrMinX(\"%1\")), Min(MbrMinY(\"%1\")), "
"Max(MbrMaxX(\"%1\")), Max(MbrMaxY(\"%1\")), Count(*) " "FROM \"%2\"" ).arg( mGeometryColumn ).arg( mTableName );
QString sql = QString( "SELECT Min(MbrMinX(%1)), Min(MbrMinY(%1)), "
"Max(MbrMaxX(%1)), Max(MbrMaxY(%1)), Count(*) " "FROM %2" )
.arg( quotedIdentifier( mGeometryColumn ) )
.arg( mQuery );
if ( !mSubsetString.isEmpty() )
{

View File

@ -257,6 +257,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
void repaintRequested();
private:
/** loads fields from input file to member attributeFields */
void loadFields();
@ -265,6 +266,10 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
* Flag indicating if the layer data source is a valid SpatiaLite layer
*/
bool valid;
/**
* Flag indicating if the layer data source is based on a query
*/
bool isQuery;
/**
* Flag indicating if the layer data source is based on a plain Table
*/
@ -289,6 +294,10 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
* Name of the table with no schema
*/
QString mTableName;
/**
* Name of the table or subquery
*/
QString mQuery;
/**
* Name of the primary key column in the table
*/
@ -363,6 +372,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
bool getTableGeometryDetails();
bool getViewGeometryDetails();
bool getVShapeGeometryDetails();
bool getQueryGeometryDetails();
bool getSridDetails();
bool getTableSummary();