Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dataprovider ogr spatialite respect provider defaults #34012

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/core/providers/ogr/qgsogrprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1209,13 +1209,18 @@ void QgsOgrProvider::loadFields()
QString defaultValue = textEncoding()->toUnicode( OGR_Fld_GetDefault( fldDef ) );
if ( !defaultValue.isEmpty() && !OGR_Fld_IsDefaultDriverSpecific( fldDef ) )
{
if ( defaultValue.startsWith( '\'' ) )
{
defaultValue = defaultValue.remove( 0, 1 );
defaultValue.chop( 1 );
defaultValue.replace( QLatin1String( "''" ), QLatin1String( "'" ) );
}
mDefaultValues.insert( createdFields, defaultValue );
}

mAttributeFields.append( newField );
createdFields++;
}

}


Expand Down Expand Up @@ -1389,13 +1394,6 @@ QVariant QgsOgrProvider::defaultValue( int fieldId ) const
resultVar = QDate::currentDate();
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
resultVar = QTime::currentTime();
else if ( defaultVal.startsWith( '\'' ) )
{
defaultVal = defaultVal.remove( 0, 1 );
defaultVal.chop( 1 );
defaultVal.replace( QLatin1String( "''" ), QLatin1String( "'" ) );
resultVar = defaultVal;
}

( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
return resultVar;
Expand Down Expand Up @@ -1584,7 +1582,12 @@ bool QgsOgrProvider::addFeaturePrivate( QgsFeature &f, Flags flags )
OGRFieldType type = OGR_Fld_GetType( fldDef );

QVariant attrVal = attrs.at( qgisAttId );
if ( attrVal.isNull() || ( type != OFTString && attrVal.toString().isEmpty() ) )
// The field value is equal to the default (that might be a provider-side expression)
if ( mDefaultValues.contains( qgisAttId ) && attrVal.toString() == mDefaultValues.value( qgisAttId ) )
{
OGR_F_UnsetField( feature.get(), ogrAttId );
}
else if ( attrVal.isNull() || ( type != OFTString && attrVal.toString().isEmpty() ) )
{
// Starting with GDAL 2.2, there are 2 concepts: unset fields and null fields
// whereas previously there was only unset fields. For a GeoJSON output,
Expand Down
150 changes: 106 additions & 44 deletions src/providers/spatialite/qgsspatialiteprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -936,7 +936,7 @@ void QgsSpatiaLiteProvider::fetchConstraints()
if ( rows >= 1 )
{
QString tableSql = QString::fromUtf8( results[ 1 ] );
QRegularExpression rx( QStringLiteral( "[(,]\\s*(?:%1|\"%1\")\\s+INTEGER PRIMARY KEY AUTOINCREMENT" ).arg( mPrimaryKey ), QRegularExpression::CaseInsensitiveOption );
QRegularExpression rx( QStringLiteral( "[(,]\\s*(?:%1|\"%1\"|`%1`)\\s+INTEGER PRIMARY KEY AUTOINCREMENT" ).arg( mPrimaryKey ), QRegularExpression::CaseInsensitiveOption );
if ( tableSql.contains( rx ) )
{
mPrimaryKeyAutoIncrement = true;
Expand All @@ -956,19 +956,22 @@ void QgsSpatiaLiteProvider::insertDefaultValue( int fieldIndex, QString defaultV

if ( mAttributeFields.at( fieldIndex ).name() != mPrimaryKey || ( mAttributeFields.at( fieldIndex ).name() == mPrimaryKey && !mPrimaryKeyAutoIncrement ) )
{
bool ok;
switch ( mAttributeFields.at( fieldIndex ).type() )
{
case QVariant::LongLong:
defaultVariant = defaultVal.toLongLong();
defaultVariant = defaultVal.toLongLong( &ok );
break;

case QVariant::Double:
defaultVariant = defaultVal.toDouble();
defaultVariant = defaultVal.toDouble( &ok );
break;

default:
{
if ( defaultVal.startsWith( '\'' ) )
// Literal string?
ok = defaultVal.startsWith( '\'' );
if ( ok )
defaultVal = defaultVal.remove( 0, 1 );
if ( defaultVal.endsWith( '\'' ) )
defaultVal.chop( 1 );
Expand All @@ -978,11 +981,56 @@ void QgsSpatiaLiteProvider::insertDefaultValue( int fieldIndex, QString defaultV
break;
}
}

if ( ! ok ) // Must be a SQL clause and not a literal
{
mDefaultValueClause.insert( fieldIndex, defaultVal );
}

}
mDefaultValues.insert( fieldIndex, defaultVariant );
mDefaultValues.insert( fieldIndex, defaultVal );
}
}


QVariant QgsSpatiaLiteProvider::defaultValue( int fieldId ) const
{
// TODO: backend-side evaluation
if ( fieldId < 0 || fieldId >= mAttributeFields.count() )
return QVariant();

QString defaultVal = mDefaultValues.value( fieldId, QString() );
if ( defaultVal.isEmpty() )
return QVariant();

QVariant resultVar = defaultVal;
if ( defaultVal == QStringLiteral( "CURRENT_TIMESTAMP" ) )
resultVar = QDateTime::currentDateTime();
else if ( defaultVal == QStringLiteral( "CURRENT_DATE" ) )
resultVar = QDate::currentDate();
else if ( defaultVal == QStringLiteral( "CURRENT_TIME" ) )
resultVar = QTime::currentTime();
else if ( defaultVal.startsWith( '\'' ) )
{
defaultVal = defaultVal.remove( 0, 1 );
defaultVal.chop( 1 );
defaultVal.replace( QLatin1String( "''" ), QLatin1String( "'" ) );
resultVar = defaultVal;
}

( void )mAttributeFields.at( fieldId ).convertCompatible( resultVar );
return resultVar;
}

QString QgsSpatiaLiteProvider::defaultValueClause( int fieldIndex ) const
{
if ( mAttributeFields.at( fieldIndex ).name() == mPrimaryKey && mPrimaryKeyAutoIncrement )
{
return tr( "Autogenerate" );
}
return mDefaultValueClause.value( fieldIndex, QString() );
}

void QgsSpatiaLiteProvider::handleError( const QString &sql, char *errorMessage, bool rollback )
{
QgsMessageLog::logMessage( tr( "SQLite error: %2\nSQL: %1" ).arg( sql, errorMessage ? errorMessage : tr( "unknown cause" ) ), tr( "SpatiaLite" ) );
Expand Down Expand Up @@ -3957,10 +4005,11 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
sqlite3_stmt *stmt = nullptr;
char *errMsg = nullptr;
bool toCommit = false;
QString sql;
QString values;
QString baseValues;
QString separator;
int ia, ret;
// SQL for single row
QString sql;

if ( flist.isEmpty() )
return true;
Expand All @@ -3971,46 +4020,58 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
toCommit = true;

sql = QStringLiteral( "INSERT INTO %1(" ).arg( QgsSqliteUtils::quotedIdentifier( mTableName ) );
values = QStringLiteral( ") VALUES (" );
QString baseSql { QStringLiteral( "INSERT INTO %1(" ).arg( QgsSqliteUtils::quotedIdentifier( mTableName ) ) };
baseValues = QStringLiteral( ") VALUES (" );
separator.clear();

if ( !mGeometryColumn.isEmpty() )
{
sql += separator + QgsSqliteUtils::quotedIdentifier( mGeometryColumn );
values += separator + geomParam();
baseSql += separator + QgsSqliteUtils::quotedIdentifier( mGeometryColumn );
baseValues += separator + geomParam();
separator = ',';
}

for ( int i = 0; i < attributevec.count(); ++i )
for ( QgsFeatureList::iterator feature = flist.begin(); feature != flist.end(); ++feature )
{
if ( i >= mAttributeFields.count() )
continue;

QString fieldname = mAttributeFields.at( i ).name();
if ( fieldname.isEmpty() || fieldname == mGeometryColumn )
continue;
QString values { baseValues };
sql = baseSql;

sql += separator + QgsSqliteUtils::quotedIdentifier( fieldname );
values += separator + '?';
separator = ',';
}
// looping on each feature to insert
QgsAttributes attributevec = feature->attributes();

sql += values;
sql += ')';
// Default indexes (to be skipped)
QList<int> defaultIndexes;

// SQLite prepared statement
ret = sqlite3_prepare_v2( mSqliteHandle, sql.toUtf8().constData(), -1, &stmt, nullptr );
if ( ret == SQLITE_OK )
{
for ( QgsFeatureList::iterator feature = flist.begin(); feature != flist.end(); ++feature )
for ( int i = 0; i < attributevec.count(); ++i )
{
// looping on each feature to insert
QgsAttributes attributevec = feature->attributes();
if ( mDefaultValues.contains( i ) && mDefaultValues.value( i ) == attributevec.at( i ).toString() )
{
defaultIndexes.push_back( i );
continue;
}

if ( i >= mAttributeFields.count() )
continue;

QString fieldname = mAttributeFields.at( i ).name();
if ( fieldname.isEmpty() || fieldname == mGeometryColumn )
{
continue;
}

sql += separator + QgsSqliteUtils::quotedIdentifier( fieldname );
values += separator + '?';
separator = ',';
}

// resetting Prepared Statement and bindings
sqlite3_reset( stmt );
sqlite3_clear_bindings( stmt );
sql += values;
sql += ')';

// SQLite prepared statement
ret = sqlite3_prepare_v2( mSqliteHandle, sql.toUtf8().constData(), -1, &stmt, nullptr );
if ( ret == SQLITE_OK )
{

// initializing the column counter
ia = 0;
Expand Down Expand Up @@ -4039,6 +4100,11 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )

for ( int i = 0; i < attributevec.count(); ++i )
{
if ( defaultIndexes.contains( i ) )
{
continue;
}

QVariant v = attributevec.at( i );

// binding values for each attribute
Expand Down Expand Up @@ -4103,6 +4169,8 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
// performing actual row insert
ret = sqlite3_step( stmt );

sqlite3_finalize( stmt );

if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
{
// update feature id
Expand All @@ -4121,14 +4189,13 @@ bool QgsSpatiaLiteProvider::addFeatures( QgsFeatureList &flist, Flags flags )
break;
}
}
} // prepared statement

sqlite3_finalize( stmt );
if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
{
ret = sqlite3_exec( mSqliteHandle, "COMMIT", nullptr, nullptr, &errMsg );
}

if ( ret == SQLITE_DONE || ret == SQLITE_ROW )
{
ret = sqlite3_exec( mSqliteHandle, "COMMIT", nullptr, nullptr, &errMsg );
}
} // prepared statement
} // BEGIN statement

if ( ret != SQLITE_OK )
Expand Down Expand Up @@ -4526,11 +4593,6 @@ QgsVectorDataProvider::Capabilities QgsSpatiaLiteProvider::capabilities() const
return mEnabledCapabilities;
}

QVariant QgsSpatiaLiteProvider::defaultValue( int fieldId ) const
{
return mDefaultValues.value( fieldId, QVariant() );
}

bool QgsSpatiaLiteProvider::skipConstraintCheck( int fieldIndex, QgsFieldConstraints::Constraint constraint, const QVariant &value ) const
{
Q_UNUSED( constraint )
Expand Down
8 changes: 7 additions & 1 deletion src/providers/spatialite/qgsspatialiteprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,9 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider

QgsFields mAttributeFields;

//! Map of field index to default value SQL fragments
QMap<int, QString> mDefaultValueClause;

//! Flag indicating if the layer data source is a valid SpatiaLite layer
bool mValid = false;

Expand Down Expand Up @@ -264,7 +267,7 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider
QString mGeometryColumn;

//! Map of field index to default value
QMap<int, QVariant> mDefaultValues;
QMap<int, QString> mDefaultValues;

//! Name of the SpatialIndex table
QString mIndexTable;
Expand Down Expand Up @@ -382,6 +385,9 @@ class QgsSpatiaLiteProvider: public QgsVectorDataProvider

friend class QgsSpatiaLiteFeatureSource;

// QgsVectorDataProvider interface
public:
virtual QString defaultValueClause( int fieldIndex ) const override;
};

class QgsSpatiaLiteProviderMetadata: public QgsProviderMetadata
Expand Down
Loading