Skip to content
Permalink
Browse files

Unify sqlite string quoting functions to a single QgsSqliteUtils::quo…

…teString

function, with tests
  • Loading branch information
nyalldawson committed Oct 4, 2018
1 parent 7e81226 commit ed35ad9ca7bfb082475eadd654bc3bb391a0d7a5
@@ -141,7 +141,7 @@ bool QgsCustomProjectionDialog::deleteCrs( const QString &id )
{
sqlite3_database_unique_ptr database;

QString sql = "delete from tbl_srs where srs_id=" + quotedValue( id );
QString sql = "delete from tbl_srs where srs_id=" + QgsSqliteUtils::quotedString( id );
QgsDebugMsg( sql );
//check the db is available
int result = database.open( QgsApplication::qgisUserDatabaseFilePath() );
@@ -191,7 +191,7 @@ void QgsCustomProjectionDialog::insertProjection( const QString &projectionAcro
else
{
// Set up the query to retrieve the projection information needed to populate the PROJECTION list
QString srsSql = "select acronym,name,notes,parameters from tbl_projection where acronym=" + quotedValue( projectionAcronym );
QString srsSql = "select acronym,name,notes,parameters from tbl_projection where acronym=" + QgsSqliteUtils::quotedString( projectionAcronym );

sqlite3_statement_unique_ptr srsPreparedStatement = srsDatabase.prepare( srsSql, srsResult );
if ( srsResult == SQLITE_OK )
@@ -201,10 +201,10 @@ void QgsCustomProjectionDialog::insertProjection( const QString &projectionAcro
QgsDebugMsg( "Trying to insert projection" );
// We have the result from system srs.db. Now insert into user db.
sql = "insert into tbl_projection(acronym,name,notes,parameters) values ("
+ quotedValue( srsPreparedStatement.columnAsText( 0 ) )
+ ',' + quotedValue( srsPreparedStatement.columnAsText( 1 ) )
+ ',' + quotedValue( srsPreparedStatement.columnAsText( 2 ) )
+ ',' + quotedValue( srsPreparedStatement.columnAsText( 3 ) )
+ QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 0 ) )
+ ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 1 ) )
+ ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 2 ) )
+ ',' + QgsSqliteUtils::quotedString( srsPreparedStatement.columnAsText( 3 ) )
+ ')';
sqlite3_statement_unique_ptr preparedStatement = database.prepare( sql, result );
if ( result != SQLITE_OK || preparedStatement.step() != SQLITE_DONE )
@@ -239,12 +239,12 @@ bool QgsCustomProjectionDialog::saveCrs( QgsCoordinateReferenceSystem parameters
else
{
sql = "update tbl_srs set description="
+ quotedValue( name )
+ ",projection_acronym=" + quotedValue( projectionAcronym )
+ ",ellipsoid_acronym=" + quotedValue( ellipsoidAcronym )
+ ",parameters=" + quotedValue( parameters.toProj4() )
+ QgsSqliteUtils::quotedString( name )
+ ",projection_acronym=" + QgsSqliteUtils::quotedString( projectionAcronym )
+ ",ellipsoid_acronym=" + QgsSqliteUtils::quotedString( ellipsoidAcronym )
+ ",parameters=" + QgsSqliteUtils::quotedString( parameters.toProj4() )
+ ",is_geo=0" // <--shamelessly hard coded for now
+ " where srs_id=" + quotedValue( id )
+ " where srs_id=" + QgsSqliteUtils::quotedString( id )
;
QgsDebugMsg( sql );
sqlite3_database_unique_ptr database;
@@ -521,12 +521,6 @@ void QgsCustomProjectionDialog::pbnCalculate_clicked()
pj_ctx_free( pContext );
}

QString QgsCustomProjectionDialog::quotedValue( QString value )
{
value.replace( '\'', QLatin1String( "''" ) );
return value.prepend( '\'' ).append( '\'' );
}

void QgsCustomProjectionDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "working_with_projections/working_with_projections.html" ) );
@@ -50,7 +50,6 @@ class APP_EXPORT QgsCustomProjectionDialog : public QDialog, private Ui::QgsCust

//helper functions
void populateList();
QString quotedValue( QString value );
bool deleteCrs( const QString &id );
bool saveCrs( QgsCoordinateReferenceSystem parameters, const QString &name, const QString &id, bool newEntry );
void insertProjection( const QString &projectionAcronym );
@@ -421,11 +421,11 @@ bool QgsNewSpatialiteLayerDialog::apply()
if ( mGeometryTypeBox->currentIndex() != 0 )
{
QString sqlAddGeom = QStringLiteral( "select AddGeometryColumn(%1,%2,%3,%4,%5)" )
.arg( quotedValue( leLayerName->text() ),
quotedValue( leGeometryColumn->text() ) )
.arg( QgsSqliteUtils::quotedString( leLayerName->text() ),
QgsSqliteUtils::quotedString( leGeometryColumn->text() ) )
.arg( mCrsId.split( ':' ).value( 1, QStringLiteral( "0" ) ).toInt() )
.arg( quotedValue( selectedType() ) )
.arg( quotedValue( selectedZM() ) );
.arg( QgsSqliteUtils::quotedString( selectedType() ) )
.arg( QgsSqliteUtils::quotedString( selectedZM() ) );
QgsDebugMsg( sqlAddGeom );

rc = sqlite3_exec( database.get(), sqlAddGeom.toUtf8(), nullptr, nullptr, &errmsg );
@@ -439,8 +439,8 @@ bool QgsNewSpatialiteLayerDialog::apply()
}

QString sqlCreateIndex = QStringLiteral( "select CreateSpatialIndex(%1,%2)" )
.arg( quotedValue( leLayerName->text() ),
quotedValue( leGeometryColumn->text() ) );
.arg( QgsSqliteUtils::quotedString( leLayerName->text() ),
QgsSqliteUtils::quotedString( leGeometryColumn->text() ) );
QgsDebugMsg( sqlCreateIndex );

rc = sqlite3_exec( database.get(), sqlCreateIndex.toUtf8(), nullptr, nullptr, &errmsg );
@@ -488,12 +488,6 @@ QString QgsNewSpatialiteLayerDialog::quotedIdentifier( QString id )
return id.prepend( '\"' ).append( '\"' );
}

QString QgsNewSpatialiteLayerDialog::quotedValue( QString value )
{
value.replace( '\'', QLatin1String( "''" ) );
return value.prepend( '\'' ).append( '\'' );
}

void QgsNewSpatialiteLayerDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "managing_data_source/create_layers.html#creating-a-new-spatialite-layer" ) );
@@ -66,7 +66,6 @@ class APP_EXPORT QgsNewSpatialiteLayerDialog: public QDialog, private Ui::QgsNew
void showHelp();

static QString quotedIdentifier( QString id );
static QString quotedValue( QString value );

QPushButton *mOkButton = nullptr;
QString mCrsId;
@@ -498,7 +498,7 @@ bool QgsCoordinateReferenceSystem::loadFromDatabase( const QString &db, const QS

QString mySql = "select srs_id,description,projection_acronym,"
"ellipsoid_acronym,parameters,srid,auth_name||':'||auth_id,is_geo "
"from tbl_srs where " + expression + '=' + quotedValue( value ) + " order by deprecated";
"from tbl_srs where " + expression + '=' + QgsSqliteUtils::quotedString( value ) + " order by deprecated";
statement = database.prepare( mySql, myResult );
// XXX Need to free memory from the error msg if one is set
if ( myResult == SQLITE_OK && statement.step() == SQLITE_ROW )
@@ -729,7 +729,7 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString &proj4String )
* We try to match the proj string to and srsid using the following logic:
* - perform a whole text search on proj4 string (if not null)
*/
myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( myProj4String ) + " order by deprecated" );
myRecord = getRecord( "select * from tbl_srs where parameters=" + QgsSqliteUtils::quotedString( myProj4String ) + " order by deprecated" );
if ( myRecord.empty() )
{
// Ticket #722 - aaronr
@@ -764,7 +764,7 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString &proj4String )
myStart2 = myLat2RegExp.indexIn( proj4String, myStart2 );
proj4StringModified.replace( myStart2 + LAT_PREFIX_LEN, myLength2 - LAT_PREFIX_LEN, lat1Str );
QgsDebugMsgLevel( "trying proj4string match with swapped lat_1,lat_2", 4 );
myRecord = getRecord( "select * from tbl_srs where parameters=" + quotedValue( proj4StringModified.trimmed() ) + " order by deprecated" );
myRecord = getRecord( "select * from tbl_srs where parameters=" + QgsSqliteUtils::quotedString( proj4StringModified.trimmed() ) + " order by deprecated" );
}
}

@@ -785,7 +785,7 @@ bool QgsCoordinateReferenceSystem::createFromProj4( const QString &proj4String )
QStringList myParams;
Q_FOREACH ( const QString &param, myProj4String.split( QRegExp( "\\s+(?=\\+)" ), QString::SkipEmptyParts ) )
{
QString arg = QStringLiteral( "' '||parameters||' ' LIKE %1" ).arg( quotedValue( QStringLiteral( "% %1 %" ).arg( param.trimmed() ) ) );
QString arg = QStringLiteral( "' '||parameters||' ' LIKE %1" ).arg( QgsSqliteUtils::quotedString( QStringLiteral( "% %1 %" ).arg( param.trimmed() ) ) );
if ( param.startsWith( QLatin1String( "+datum=" ) ) )
{
datum = arg;
@@ -1234,8 +1234,8 @@ long QgsCoordinateReferenceSystem::findMatchingProj()
// needed to populate the list
QString mySql = QString( "select srs_id,parameters from tbl_srs where "
"projection_acronym=%1 and ellipsoid_acronym=%2 order by deprecated" )
.arg( quotedValue( d->mProjectionAcronym ),
quotedValue( d->mEllipsoidAcronym ) );
.arg( QgsSqliteUtils::quotedString( d->mProjectionAcronym ),
QgsSqliteUtils::quotedString( d->mEllipsoidAcronym ) );
// Get the full path name to the sqlite3 spatial reference database.
QString myDatabaseFileName = QgsApplication::srsDatabaseFilePath();

@@ -1620,19 +1620,19 @@ long QgsCoordinateReferenceSystem::saveAsUserCrs( const QString &name )
{
mySql = "insert into tbl_srs (srs_id,description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
+ QString::number( USER_CRS_START_ID )
+ ',' + quotedValue( name )
+ ',' + quotedValue( projectionAcronym() )
+ ',' + quotedValue( ellipsoidAcronym() )
+ ',' + quotedValue( toProj4() )
+ ',' + QgsSqliteUtils::quotedString( name )
+ ',' + QgsSqliteUtils::quotedString( projectionAcronym() )
+ ',' + QgsSqliteUtils::quotedString( ellipsoidAcronym() )
+ ',' + QgsSqliteUtils::quotedString( toProj4() )
+ ",0)"; // <-- is_geo shamelessly hard coded for now
}
else
{
mySql = "insert into tbl_srs (description,projection_acronym,ellipsoid_acronym,parameters,is_geo) values ("
+ quotedValue( name )
+ ',' + quotedValue( projectionAcronym() )
+ ',' + quotedValue( ellipsoidAcronym() )
+ ',' + quotedValue( toProj4() )
+ QgsSqliteUtils::quotedString( name )
+ ',' + QgsSqliteUtils::quotedString( projectionAcronym() )
+ ',' + QgsSqliteUtils::quotedString( ellipsoidAcronym() )
+ ',' + QgsSqliteUtils::quotedString( toProj4() )
+ ",0)"; // <-- is_geo shamelessly hard coded for now
}
sqlite3_database_unique_ptr database;
@@ -1707,12 +1707,6 @@ long QgsCoordinateReferenceSystem::getRecordCount()
return myRecordCount;
}

QString QgsCoordinateReferenceSystem::quotedValue( QString value )
{
value.replace( '\'', QLatin1String( "''" ) );
return value.prepend( '\'' ).append( '\'' );
}

// adapted from gdal/ogr/ogr_srs_dict.cpp
bool QgsCoordinateReferenceSystem::loadWkts( QHash<int, QString> &wkts, const char *filename )
{
@@ -1951,8 +1945,8 @@ int QgsCoordinateReferenceSystem::syncDatabase()
{
errMsg = nullptr;
sql = QStringLiteral( "UPDATE tbl_srs SET parameters=%1,description=%2,deprecated=%3 WHERE auth_name='EPSG' AND auth_id=%4" )
.arg( quotedValue( proj4 ) )
.arg( quotedValue( name ) )
.arg( QgsSqliteUtils::quotedString( proj4 ) )
.arg( QgsSqliteUtils::quotedString( name ) )
.arg( deprecated ? 1 : 0 )
.arg( it.key() );

@@ -1989,10 +1983,10 @@ int QgsCoordinateReferenceSystem::syncDatabase()
}

sql = QStringLiteral( "INSERT INTO tbl_srs(description,projection_acronym,ellipsoid_acronym,parameters,srid,auth_name,auth_id,is_geo,deprecated) VALUES (%1,%2,%3,%4,%5,'EPSG',%5,%6,%7)" )
.arg( quotedValue( name ),
quotedValue( projRegExp.cap( 1 ) ),
quotedValue( ellps ),
quotedValue( proj4 ) )
.arg( QgsSqliteUtils::quotedString( name ),
QgsSqliteUtils::quotedString( projRegExp.cap( 1 ) ),
QgsSqliteUtils::quotedString( ellps ),
QgsSqliteUtils::quotedString( proj4 ) )
.arg( it.key() )
.arg( OSRIsGeographic( crs ) )
.arg( deprecated ? 1 : 0 );
@@ -2081,9 +2075,9 @@ int QgsCoordinateReferenceSystem::syncDatabase()
if ( proj4 != params )
{
sql = QStringLiteral( "UPDATE tbl_srs SET parameters=%1 WHERE auth_name=%2 AND auth_id=%3" )
.arg( quotedValue( proj4 ),
quotedValue( auth_name ),
quotedValue( auth_id ) );
.arg( QgsSqliteUtils::quotedString( proj4 ),
QgsSqliteUtils::quotedString( auth_name ),
QgsSqliteUtils::quotedString( auth_id ) );

if ( sqlite3_exec( database.get(), sql.toUtf8(), nullptr, nullptr, &errMsg ) == SQLITE_OK )
{
@@ -2291,7 +2285,7 @@ bool QgsCoordinateReferenceSystem::syncDatumTransform( const QString &dbPath )
int idx = map[i].idx;
Q_ASSERT( idx != -1 );
Q_ASSERT( idx < n );
v.insert( i, *values[ idx ] ? quotedValue( values[idx] ) : QStringLiteral( "NULL" ) );
v.insert( i, *values[ idx ] ? QgsSqliteUtils::quotedString( values[idx] ) : QStringLiteral( "NULL" ) );
}
CSLDestroy( values );

@@ -741,9 +741,6 @@ class CORE_EXPORT QgsCoordinateReferenceSystem
//! Helper for getting number of user CRS already in db
long getRecordCount();

//! Helper for sql-safe value quoting
static QString quotedValue( QString value );

/**
* Initialize the CRS object by looking up CRS database in path given in db argument,
* using first CRS entry where expression = 'value'
@@ -91,6 +91,16 @@ sqlite3_statement_unique_ptr sqlite3_database_unique_ptr::prepare( const QString
return s;
}

QString QgsSqliteUtils::quotedString( const QString &value )
{
if ( value.isNull() )
return QStringLiteral( "NULL" );

QString v = value;
v.replace( '\'', QLatin1String( "''" ) );
return v.prepend( '\'' ).append( '\'' );
}

QString QgsSqlite3Mprintf( const char *format, ... )
{
va_list ap;
@@ -135,8 +135,24 @@ class CORE_EXPORT sqlite3_database_unique_ptr : public std::unique_ptr< sqlite3,
* argument will be filled with the sqlite3 result code.
*/
sqlite3_statement_unique_ptr prepare( const QString &sql, int &resultCode ) const;

};

/**
* Contains utilities for working with Sqlite data sources.
* \note not available in Python bindings
* \since QGIS 3.4
*/
class CORE_EXPORT QgsSqliteUtils
{
public:

/**
* Returns a quoted string \a value, surround by ' characters and with special
* characters correctly escaped.
*/
static QString quotedString( const QString &value );
};

/**
* Wraps sqlite3_mprintf() by automatically freeing the memory.
@@ -454,15 +454,6 @@ bool QgsSpatiaLiteConnection::getTableInfo( sqlite3 *handle, bool loadGeometryle
return false;
}

QString QgsSpatiaLiteConnection::quotedValue( QString value ) const
{
if ( value.isNull() )
return QStringLiteral( "NULL" );

value.replace( '\'', QLatin1String( "''" ) );
return value.prepend( '\'' ).append( '\'' );
}

bool QgsSpatiaLiteConnection::checkGeometryColumnsAuth( sqlite3 *handle )
{
int ret;
@@ -624,8 +615,8 @@ bool QgsSpatiaLiteConnection::isDeclaredHidden( sqlite3 *handle, const QString &
return false;
// checking if some Layer has been declared as HIDDEN
QString sql = QString( "SELECT hidden FROM geometry_columns_auth"
" WHERE f_table_name=%1 and f_geometry_column=%2" ).arg( quotedValue( table ),
quotedValue( geom ) );
" WHERE f_table_name=%1 and f_geometry_column=%2" ).arg( QgsSqliteUtils::quotedString( table ),
QgsSqliteUtils::quotedString( geom ) );

ret = sqlite3_get_table( handle, sql.toUtf8().constData(), &results, &rows, &columns, &errMsg );
if ( ret != SQLITE_OK )
@@ -104,9 +104,6 @@ class QgsSpatiaLiteConnection : public QObject
*/
bool getTableInfoAbstractInterface( sqlite3 *handle, bool loadGeometrylessTables );

//! Cleaning well-formatted SQL strings
QString quotedValue( QString value ) const;

//! Checks if geometry_columns_auth table exists
bool checkGeometryColumnsAuth( sqlite3 *handle );

0 comments on commit ed35ad9

Please sign in to comment.
You can’t perform that action at this time.