Skip to content

Commit ccc67ef

Browse files
committedJun 2, 2016
Rename attributes support for postgres provider
1 parent 251474a commit ccc67ef

File tree

4 files changed

+114
-8
lines changed

4 files changed

+114
-8
lines changed
 

‎src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1123,7 +1123,7 @@ bool QgsPostgresProvider::hasSufficientPermsAndCapabilities()
11231123
testAccess = connectionRO()->PQexec( sql );
11241124
if ( testAccess.PQresultStatus() == PGRES_TUPLES_OK && testAccess.PQntuples() == 1 )
11251125
{
1126-
mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes;
1126+
mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes | QgsVectorDataProvider::DeleteAttributes | QgsVectorDataProvider::RenameAttributes;
11271127
}
11281128
}
11291129
}
@@ -2251,6 +2251,66 @@ bool QgsPostgresProvider::deleteAttributes( const QgsAttributeIds& ids )
22512251
return returnvalue;
22522252
}
22532253

2254+
bool QgsPostgresProvider::renameAttributes( const QgsFieldNameMap& renamedAttributes )
2255+
{
2256+
if ( mIsQuery )
2257+
return false;
2258+
2259+
2260+
QString sql = "BEGIN;";
2261+
2262+
QgsFieldNameMap::const_iterator renameIt = renamedAttributes.constBegin();
2263+
bool returnvalue = true;
2264+
for ( ; renameIt != renamedAttributes.constEnd(); ++renameIt )
2265+
{
2266+
int fieldIndex = renameIt.key();
2267+
if ( fieldIndex < 0 || fieldIndex >= mAttributeFields.count() )
2268+
{
2269+
pushError( tr( "Invalid attribute index: %1" ).arg( fieldIndex ) );
2270+
return false;
2271+
}
2272+
if ( mAttributeFields.indexFromName( renameIt.value() ) >= 0 )
2273+
{
2274+
//field name already in use
2275+
pushError( tr( "Error renaming field %1: name '%2' already exists" ).arg( fieldIndex ).arg( renameIt.value() ) );
2276+
return false;
2277+
}
2278+
2279+
sql += QString( "ALTER TABLE %1 RENAME COLUMN %2 TO %3;" )
2280+
.arg( mQuery,
2281+
quotedIdentifier( mAttributeFields.at( fieldIndex ).name() ),
2282+
quotedIdentifier( renameIt.value() ) );
2283+
}
2284+
sql += "COMMIT;";
2285+
2286+
QgsPostgresConn* conn = connectionRW();
2287+
if ( !conn )
2288+
{
2289+
return false;
2290+
}
2291+
conn->lock();
2292+
2293+
try
2294+
{
2295+
conn->begin();
2296+
//send sql statement and do error handling
2297+
QgsPostgresResult result( conn->PQexec( sql ) );
2298+
if ( result.PQresultStatus() != PGRES_COMMAND_OK )
2299+
throw PGException( result );
2300+
returnvalue = conn->commit();
2301+
}
2302+
catch ( PGException &e )
2303+
{
2304+
pushError( tr( "PostGIS error while renaming attributes: %1" ).arg( e.errorMessage() ) );
2305+
conn->rollback();
2306+
returnvalue = false;
2307+
}
2308+
2309+
loadFields();
2310+
conn->unlock();
2311+
return returnvalue;
2312+
}
2313+
22542314
bool QgsPostgresProvider::changeAttributeValues( const QgsChangedAttributesMap &attr_map )
22552315
{
22562316
bool returnvalue = true;

‎src/providers/postgres/qgspostgresprovider.h

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -196,15 +196,9 @@ class QgsPostgresProvider : public QgsVectorDataProvider
196196
@return true in case of success and false in case of failure*/
197197
bool deleteFeatures( const QgsFeatureIds & id ) override;
198198

199-
/** Adds new attributes
200-
@param name map with attribute name as key and type as value
201-
@return true in case of success and false in case of failure*/
202199
bool addAttributes( const QList<QgsField> &attributes ) override;
203-
204-
/** Deletes existing attributes
205-
@param names of the attributes to delete
206-
@return true in case of success and false in case of failure*/
207200
bool deleteAttributes( const QgsAttributeIds &name ) override;
201+
virtual bool renameAttributes( const QgsFieldNameMap& renamedAttributes ) override;
208202

209203
/** Changes attribute values of existing features
210204
@param attr_map a map containing the new attributes. The integer is the feature id,

‎tests/src/python/test_provider_postgres.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,44 @@ def testDomainTypes(self):
231231
if 'precision' in e:
232232
self.assertEqual(fields.at(fields.indexFromName(f)).precision(), e['precision'])
233233

234+
def testRenameAttributes(self):
235+
''' Test renameAttributes() '''
236+
vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % (self.dbconn), "renames", "postgres")
237+
provider = vl.dataProvider()
238+
provider.renameAttributes({1: 'field1', 2: 'field2'})
239+
240+
# bad rename
241+
self.assertFalse(provider.renameAttributes({-1: 'not_a_field'}))
242+
self.assertFalse(provider.renameAttributes({100: 'not_a_field'}))
243+
# already exists
244+
self.assertFalse(provider.renameAttributes({1: 'field2'}))
245+
246+
# rename one field
247+
self.assertTrue(provider.renameAttributes({1: 'newname'}))
248+
self.assertEqual(provider.fields().at(1).name(), 'newname')
249+
vl.updateFields()
250+
fet = next(vl.getFeatures())
251+
self.assertEqual(fet.fields()[1].name(), 'newname')
252+
253+
# rename two fields
254+
self.assertTrue(provider.renameAttributes({1: 'newname2', 2: 'another'}))
255+
self.assertEqual(provider.fields().at(1).name(), 'newname2')
256+
self.assertEqual(provider.fields().at(2).name(), 'another')
257+
vl.updateFields()
258+
fet = next(vl.getFeatures())
259+
self.assertEqual(fet.fields()[1].name(), 'newname2')
260+
self.assertEqual(fet.fields()[2].name(), 'another')
261+
262+
# close layer and reopen, then recheck to confirm that changes were saved to db
263+
del vl
264+
vl = None
265+
vl = QgsVectorLayer('%s table="qgis_test"."rename_table" sql=' % (self.dbconn), "renames", "postgres")
266+
provider = vl.dataProvider()
267+
self.assertEqual(provider.fields().at(1).name(), 'newname2')
268+
self.assertEqual(provider.fields().at(2).name(), 'another')
269+
fet = next(vl.getFeatures())
270+
self.assertEqual(fet.fields()[1].name(), 'newname2')
271+
self.assertEqual(fet.fields()[2].name(), 'another')
234272

235273
if __name__ == '__main__':
236274
unittest.main()

‎tests/testdata/provider/testdata_pg.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,3 +398,17 @@ CREATE TABLE qgis_test.domains
398398
fld_text_domain qgis_test.text_domain,
399399
fld_numeric_domain qgis_test.numeric_domain
400400
);
401+
402+
403+
--------------------------------------
404+
-- Temporary table for testing renaming fields
405+
--
406+
407+
CREATE TABLE qgis_test.rename_table
408+
(
409+
gid serial NOT NULL,
410+
field1 text,
411+
field2 text
412+
);
413+
414+
INSERT INTO qgis_test.rename_table (field1,field2) VALUES ('a','b');

0 commit comments

Comments
 (0)
Please sign in to comment.