Skip to content

Commit

Permalink
Merge branch 'master' into code_modernization
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn authored Apr 7, 2019
2 parents cbecf25 + 4a87cc9 commit 4852bac
Show file tree
Hide file tree
Showing 22 changed files with 415 additions and 85 deletions.
1 change: 0 additions & 1 deletion .ci/travis/linux/scripts/test_blacklist.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# black list
PyQgsLocalServer
PyQgsPalLabelingServer
qgis_composermapgridtest
qgis_composerutils
PyQgsAppStartup

Expand Down
5 changes: 3 additions & 2 deletions python/server/auto_generated/qgsserverparameters.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,12 @@ Converts the parameter into a string. If ``defaultValue`` is true
and current value is empty, then the default value is returned.
%End

QStringList toStringList( char delimiter = ',' ) const;
QStringList toStringList( char delimiter = ',', bool skipEmptyParts = true ) const;
%Docstring
Converts the parameter into a list of strings.
Converts the parameter into a list of strings

:param delimiter: The character used for delimiting
:param skipEmptyParts: To use QString.SkipEmptyParts for splitting

:return: A list of strings
%End
Expand Down
18 changes: 18 additions & 0 deletions python/server/auto_generated/qgsserversettings.sip.in
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,24 @@ Show group (thousand) separator

:return: if group separator must be shown, default to ``False``.

.. versionadded:: 3.8
%End

int wmsMaxHeight() const;
%Docstring
Returns the server-wide max height of a WMS GetMap request. The lower one of this and the project configuration is used.

:return: the max height of a WMS GetMap request.

.. versionadded:: 3.8
%End

int wmsMaxWidth() const;
%Docstring
Returns the server-wide max width of a WMS GetMap request. The lower one of this and the project configuration is used.

:return: the max width of a WMS GetMap request.

.. versionadded:: 3.8
%End

Expand Down
90 changes: 62 additions & 28 deletions src/providers/postgres/qgspostgresprovider.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ bool QgsPostgresProvider::loadFields()
}


QMap<int, QMap<int, QString> > fmtFieldTypeMap, descrMap, defValMap;
QMap<int, QMap<int, QString> > fmtFieldTypeMap, descrMap, defValMap, identityMap;
QMap<int, QMap<int, int> > attTypeIdMap;
QMap<int, QMap<int, bool> > notNullMap, uniqueMap;
if ( result.PQnfields() > 0 )
Expand Down Expand Up @@ -789,14 +789,17 @@ bool QgsPostgresProvider::loadFields()
QString tableoidsFilter = '(' + tableoidsList.join( QStringLiteral( "," ) ) + ')';

// Collect formatted field types
sql = "SELECT attrelid, attnum, pg_catalog.format_type(atttypid,atttypmod), pg_catalog.col_description(attrelid,attnum), pg_catalog.pg_get_expr(adbin,adrelid), atttypid, attnotnull::int, indisunique::int"
" FROM pg_attribute"
" LEFT OUTER JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum"
sql = QStringLiteral(
"SELECT attrelid, attnum, pg_catalog.format_type(atttypid,atttypmod), pg_catalog.col_description(attrelid,attnum), pg_catalog.pg_get_expr(adbin,adrelid), atttypid, attnotnull::int, indisunique::int%1"
" FROM pg_attribute"
" LEFT OUTER JOIN pg_attrdef ON attrelid=adrelid AND attnum=adnum"

// find unique constraints if present. Text cast required to handle int2vector comparison. Distinct required as multiple unique constraints may exist
" LEFT OUTER JOIN ( SELECT DISTINCT indrelid, indkey, indisunique FROM pg_index WHERE indisunique ) uniq ON attrelid=indrelid AND attnum::text=indkey::text "
// find unique constraints if present. Text cast required to handle int2vector comparison. Distinct required as multiple unique constraints may exist
" LEFT OUTER JOIN ( SELECT DISTINCT indrelid, indkey, indisunique FROM pg_index WHERE indisunique ) uniq ON attrelid=indrelid AND attnum::text=indkey::text "

" WHERE attrelid IN %2"
).arg( connectionRO()->pgVersion() >= 100000 ? QStringLiteral( ", attidentity" ) : QString() ).arg( tableoidsFilter );

" WHERE attrelid IN " + tableoidsFilter;
QgsPostgresResult fmtFieldTypeResult( connectionRO()->PQexec( sql ) );
for ( int i = 0; i < fmtFieldTypeResult.PQntuples(); ++i )
{
Expand All @@ -808,18 +811,21 @@ bool QgsPostgresProvider::loadFields()
int attType = fmtFieldTypeResult.PQgetvalue( i, 5 ).toInt();
bool attNotNull = fmtFieldTypeResult.PQgetvalue( i, 6 ).toInt();
bool uniqueConstraint = fmtFieldTypeResult.PQgetvalue( i, 7 ).toInt();
QString attIdentity = connectionRO()->pgVersion() >= 100000 ? fmtFieldTypeResult.PQgetvalue( i, 8 ) : " ";
fmtFieldTypeMap[attrelid][attnum] = formatType;
descrMap[attrelid][attnum] = descr;
defValMap[attrelid][attnum] = defVal;
attTypeIdMap[attrelid][attnum] = attType;
notNullMap[attrelid][attnum] = attNotNull;
uniqueMap[attrelid][attnum] = uniqueConstraint;
identityMap[attrelid][attnum] = attIdentity.isEmpty() ? " " : attIdentity;
}
}
}

QSet<QString> fields;
mAttributeFields.clear();
mIdentityFields.clear();
for ( int i = 0; i < result.PQnfields(); i++ )
{
QString fieldName = result.PQfname( i );
Expand Down Expand Up @@ -1052,12 +1058,13 @@ bool QgsPostgresProvider::loadFields()
QgsField newField = QgsField( fieldName, fieldType, fieldTypeName, fieldSize, fieldPrec, fieldComment, fieldSubType );

QgsFieldConstraints constraints;
if ( notNullMap[tableoid][attnum] || mPrimaryKeyAttrs.contains( i ) )
if ( notNullMap[tableoid][attnum] || ( mPrimaryKeyAttrs.size() == 1 && mPrimaryKeyAttrs[0] == i ) || identityMap[tableoid][attnum] != ' ' )
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
if ( uniqueMap[tableoid][attnum] || mPrimaryKeyAttrs.contains( i ) )
if ( uniqueMap[tableoid][attnum] || ( mPrimaryKeyAttrs.size() == 1 && mPrimaryKeyAttrs[0] == i ) || identityMap[tableoid][attnum] != ' ' )
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
newField.setConstraints( constraints );

mIdentityFields.insert( mAttributeFields.size(), identityMap[tableoid][attnum][0].toLatin1() );
mAttributeFields.append( newField );
}

Expand Down Expand Up @@ -1333,19 +1340,40 @@ bool QgsPostgresProvider::determinePrimaryKey()
QgsDebugMsg( QStringLiteral( "Relation is a table. Checking to see if it has an oid column." ) );

mPrimaryKeyAttrs.clear();
mPrimaryKeyType = PktUnknown;

// If there is an oid on the table, use that instead,
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" ).arg( quotedValue( mQuery ) );
if ( connectionRO()->pgVersion() >= 100000 )
{
// If there is an generated id on the table, use that instead,
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attidentity IN ('a','d') AND attrelid=regclass(%1) LIMIT 1" ).arg( quotedValue( mQuery ) );
res = connectionRO()->PQexec( sql );
if ( res.PQntuples() == 1 )
{
// Could warn the user here that performance will suffer if
// attribute isn't indexed (and that they may want to add a
// primary key to the table)
int idx = fieldNameIndex( res.PQgetvalue( 0, 0 ) );
mPrimaryKeyType = pkType( mAttributeFields.at( idx ) );
mPrimaryKeyAttrs << idx;
}
}

res = connectionRO()->PQexec( sql );
if ( res.PQntuples() == 1 )
if ( mPrimaryKeyType == PktUnknown )
{
// Could warn the user here that performance will suffer if
// oid isn't indexed (and that they may want to add a
// primary key to the table)
mPrimaryKeyType = PktOid;
// If there is an oid on the table, use that instead,
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attname='oid' AND attrelid=regclass(%1)" ).arg( quotedValue( mQuery ) );

res = connectionRO()->PQexec( sql );
if ( res.PQntuples() == 1 )
{
// Could warn the user here that performance will suffer if
// oid isn't indexed (and that they may want to add a
// primary key to the table)
mPrimaryKeyType = PktOid;
}
}
else

if ( mPrimaryKeyType == PktUnknown )
{
sql = QStringLiteral( "SELECT attname FROM pg_attribute WHERE attname='ctid' AND attrelid=regclass(%1)" ).arg( quotedValue( mQuery ) );

Expand All @@ -1357,10 +1385,11 @@ bool QgsPostgresProvider::determinePrimaryKey()
QgsMessageLog::logMessage( tr( "Primary key is ctid - changing of existing features disabled (%1; %2)" ).arg( mGeometryColumn, mQuery ) );
mEnabledCapabilities &= ~( QgsVectorDataProvider::DeleteFeatures | QgsVectorDataProvider::ChangeAttributeValues | QgsVectorDataProvider::ChangeGeometries | QgsVectorDataProvider::ChangeFeatures );
}
else
{
QgsMessageLog::logMessage( tr( "The table has no column suitable for use as a key. QGIS requires a primary key, a PostgreSQL oid column or a ctid for tables." ), tr( "PostGIS" ) );
}
}

if ( mPrimaryKeyType == PktUnknown )
{
QgsMessageLog::logMessage( tr( "The table has no column suitable for use as a key. QGIS requires a primary key, a PostgreSQL oid column or a ctid for tables." ), tr( "PostGIS" ) );
}
}
else if ( type == Relkind::View || type == Relkind::MaterializedView )
Expand Down Expand Up @@ -1428,14 +1457,13 @@ bool QgsPostgresProvider::determinePrimaryKey()
determinePrimaryKeyFromUriKeyColumn();
}

const auto constMPrimaryKeyAttrs = mPrimaryKeyAttrs;
for ( int fieldIdx : constMPrimaryKeyAttrs )
if ( mPrimaryKeyAttrs.size() == 1 )
{
//primary keys are unique, not null
QgsFieldConstraints constraints = mAttributeFields.at( fieldIdx ).constraints();
QgsFieldConstraints constraints = mAttributeFields.at( mPrimaryKeyAttrs[0] ).constraints();
constraints.setConstraint( QgsFieldConstraints::ConstraintUnique, QgsFieldConstraints::ConstraintOriginProvider );
constraints.setConstraint( QgsFieldConstraints::ConstraintNotNull, QgsFieldConstraints::ConstraintOriginProvider );
mAttributeFields[ fieldIdx ].setConstraints( constraints );
mAttributeFields[ mPrimaryKeyAttrs[0] ].setConstraints( constraints );
}

mValid = mPrimaryKeyType != PktUnknown;
Expand Down Expand Up @@ -2031,7 +2059,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )

// Prepare the INSERT statement
QString insert = QStringLiteral( "INSERT INTO %1(" ).arg( mQuery );
QString values = QStringLiteral( ") VALUES (" );
QString values;
QString delim;
int offset = 1;

Expand All @@ -2051,6 +2079,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
// is a sequence, and that none of the features have a value set for that
// column, then we can completely omit inserting it.
bool skipSinglePKField = false;
bool overrideIdentity = false;

if ( ( mPrimaryKeyType == PktInt || mPrimaryKeyType == PktFidMap || mPrimaryKeyType == PktUint64 ) )
{
Expand Down Expand Up @@ -2079,6 +2108,8 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
{
for ( int idx : mPrimaryKeyAttrs )
{
if ( mIdentityFields[idx] == 'a' )
overrideIdentity = true;
insert += delim + quotedIdentifier( field( idx ).name() );
values += delim + QStringLiteral( "$%1" ).arg( defaultValues.size() + offset );
delim = ',';
Expand Down Expand Up @@ -2123,6 +2154,9 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )

insert += delim + quotedIdentifier( fieldname );

if ( mIdentityFields[idx] == 'a' )
overrideIdentity = true;

QString defVal = defaultValueClause( idx );

if ( i == flist.size() )
Expand Down Expand Up @@ -2187,7 +2221,7 @@ bool QgsPostgresProvider::addFeatures( QgsFeatureList &flist, Flags flags )
delim = ',';
}

insert += values + ')';
insert += QStringLiteral( ") %1VALUES (%2)" ).arg( overrideIdentity ? "OVERRIDING SYSTEM VALUE " : "" ).arg( values );

if ( !( flags & QgsFeatureSink::FastInsert ) )
{
Expand Down
1 change: 1 addition & 0 deletions src/providers/postgres/qgspostgresprovider.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ class QgsPostgresProvider : public QgsVectorDataProvider
QgsAttrPalIndexNameHash mAttrPalIndexName;

QgsFields mAttributeFields;
QHash<int, char> mIdentityFields;
QString mDataComment;

//! Data source URI struct for this layer
Expand Down
16 changes: 14 additions & 2 deletions src/server/qgsserverparameters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,21 @@ QString QgsServerParameterDefinition::toString( const bool defaultValue ) const
return value;
}

QStringList QgsServerParameterDefinition::toStringList( const char delimiter ) const
QStringList QgsServerParameterDefinition::toStringList( const char delimiter, const bool skipEmptyParts ) const
{
return toString().split( delimiter, QString::SkipEmptyParts );
if ( skipEmptyParts )
{
return toString().split( delimiter, QString::SkipEmptyParts );
}
else
{
QStringList list;
if ( !toString().isEmpty() )
{
list = toString().split( delimiter, QString::KeepEmptyParts );
}
return list;
}
}

QList<QgsGeometry> QgsServerParameterDefinition::toGeomList( bool &ok, const char delimiter ) const
Expand Down
5 changes: 3 additions & 2 deletions src/server/qgsserverparameters.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,12 @@ class SERVER_EXPORT QgsServerParameterDefinition
QString toString( bool defaultValue = false ) const;

/**
* Converts the parameter into a list of strings.
* Converts the parameter into a list of strings
* \param delimiter The character used for delimiting
* \param skipEmptyParts To use QString::SkipEmptyParts for splitting
* \returns A list of strings
*/
QStringList toStringList( char delimiter = ',' ) const;
QStringList toStringList( char delimiter = ',', bool skipEmptyParts = true ) const;

/**
* Converts the parameter into a list of integers.
Expand Down
Loading

0 comments on commit 4852bac

Please sign in to comment.