Skip to content

Commit

Permalink
attribute table: add attributes before applying attribute changes, fixes
Browse files Browse the repository at this point in the history
 #763

please test


git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@7642 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
jef committed Nov 22, 2007
1 parent 4fa2d65 commit 66d22b1
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 97 deletions.
54 changes: 34 additions & 20 deletions src/app/qgsattributetable.cpp
Expand Up @@ -408,7 +408,7 @@ void QgsAttributeTable::copySelectedRows()

bool QgsAttributeTable::commitChanges(QgsVectorLayer* layer)
{
bool isSuccessful = FALSE;
bool isSuccessful = false;

if(layer)
{
Expand All @@ -427,28 +427,42 @@ bool QgsAttributeTable::commitChanges(QgsVectorLayer* layer)
deletedIds.insert(provider->indexFromFieldName(*it));
}

QgsChangedAttributesMap attributeChanges; //convert mChangedValues to QgsChangedAttributesMap
int fieldIndex;
isSuccessful = true;
if( !mAddedAttributes.empty() )
{
// add new attributes beforehand, so attribute changes can be applied
isSuccessful = layer->commitAttributeChanges(QgsAttributeIds(), mAddedAttributes, QgsChangedAttributesMap());
}

QMap<int, QMap<QString, QString> >::const_iterator att_it = mChangedValues.constBegin();
for(; att_it != mChangedValues.constEnd(); ++att_it)
if(isSuccessful)
{
QgsAttributeMap newAttMap;
QMap<QString, QString>::const_iterator record_it = att_it->constBegin();
for(; record_it != att_it->constEnd(); ++record_it)
QgsChangedAttributesMap attributeChanges; //convert mChangedValues to QgsChangedAttributesMap
int fieldIndex;

QMap<int, QMap<QString, QString> >::const_iterator att_it = mChangedValues.constBegin();
for(; att_it != mChangedValues.constEnd(); ++att_it)
{
fieldIndex = provider->indexFromFieldName(record_it.key());
if(fieldIndex != -1)
{
newAttMap.insert(fieldIndex, record_it.value());
}
}
attributeChanges.insert(att_it.key(), newAttMap);
}

isSuccessful = layer->commitAttributeChanges(deletedIds,
mAddedAttributes,
attributeChanges);
QgsAttributeMap newAttMap;
QMap<QString, QString>::const_iterator record_it = att_it->constBegin();
for(; record_it != att_it->constEnd(); ++record_it)
{
fieldIndex = provider->indexFromFieldName(record_it.key());
if(fieldIndex != -1)
{
newAttMap.insert(fieldIndex, record_it.value());
}
else
{
QgsDebugMsg("Changed attribute " + record_it.key() + " not found");
}
}
attributeChanges.insert(att_it.key(), newAttMap);
}

isSuccessful = layer->commitAttributeChanges(deletedIds,
QgsNewAttributesMap(),
attributeChanges);
}
}
}

Expand Down
157 changes: 81 additions & 76 deletions src/providers/postgres/qgspostgresprovider.cpp
Expand Up @@ -144,82 +144,8 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
calculateExtents();
getFeatureCount();

// Get the relation oid for use in later queries
sql = "SELECT oid FROM pg_class WHERE relname = '" + mTableName + "' AND relnamespace = ("
"SELECT oid FROM pg_namespace WHERE nspname = '" + mSchemaName + "')";
PGresult *tresult= PQexec(connection, (const char *)(sql.utf8()));
QString tableoid = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

// Get the table description
sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = 0";
tresult = PQexec(connection, (const char*) sql.utf8());
if (PQntuples(tresult) > 0)
mDataComment = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

// Populate the field vector for this layer. The field vector contains
// field name, type, length, and precision (if numeric)
sql = "select * from " + mSchemaTableName + " limit 0";

PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;

// The queries inside this loop could possibly be combined into one
// single query - this would make the code run faster.

for (int i=0; i < PQnfields(result); i++)
{
QString fieldName = PQfname(result, i);
int fldtyp = PQftype(result, i);
QString typOid = QString().setNum(fldtyp);
int fieldModifier = PQfmod(result, i);
QString fieldComment("");

sql = "SELECT typname, typlen FROM pg_type WHERE "
"oid = (SELECT typelem FROM pg_type WHERE "
"typelem = " + typOid + " AND typlen = -1)";

PGresult* oidResult = PQexec(connection, (const char *) sql);
QString fieldTypeName = PQgetvalue(oidResult, 0, 0);
QString fieldSize = PQgetvalue(oidResult, 0, 1);
PQclear(oidResult);

sql = "SELECT attnum FROM pg_attribute WHERE "
"attrelid = " + tableoid + " AND attname = '" + fieldName + "'";
PGresult *tresult = PQexec(connection, (const char *)(sql.utf8()));
QString attnum = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = " + attnum;
tresult = PQexec(connection, (const char*)(sql.utf8()));
if (PQntuples(tresult) > 0)
fieldComment = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

QgsDebugMsg("Field: " + attnum + " maps to " + QString::number( i ) + " " + fieldName + ", "
+ fieldTypeName + " (" + QString::number(fldtyp) + "), " + fieldSize + ", " + QString::number(fieldModifier));

if(fieldName!=geometryColumn)
{

QVariant::Type fieldType;
if (fieldTypeName.find("int") != -1 || fieldTypeName.find("serial") != -1)
fieldType = QVariant::Int;
else if (fieldTypeName == "real" || fieldTypeName == "double precision" || \
fieldTypeName.find("float") != -1)
fieldType = QVariant::Double;
else if (fieldTypeName != "bytea" )
fieldType = QVariant::String;
else
continue;

attributeFields.insert(i, QgsField(fieldName, fieldType, fieldTypeName, fieldSize.toInt(), fieldModifier, fieldComment));
}
}
PQclear(result);
// load the field list
loadFields();

// set the primary key
getPrimaryKey();
Expand Down Expand Up @@ -778,6 +704,7 @@ void QgsPostgresProvider::reset()
QString move = "move 0 in qgisf"; //move cursor to first record
PQexec(connection, (const char *)(move.utf8()));
mFeatureQueue.empty();
loadFields();
}

/** @todo XXX Perhaps this should be promoted to QgsDataProvider? */
Expand All @@ -796,6 +723,84 @@ QString QgsPostgresProvider::endianString()
}
}

void QgsPostgresProvider::loadFields()
{
QgsDebugMsg("Loading fields for table " + mTableName);

// Get the relation oid for use in later queries
QString sql = "SELECT oid FROM pg_class WHERE relname = '" + mTableName + "' AND relnamespace = ("
"SELECT oid FROM pg_namespace WHERE nspname = '" + mSchemaName + "')";
PGresult *tresult= PQexec(connection, (const char *)(sql.utf8()));
QString tableoid = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

// Get the table description
sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = 0";
tresult = PQexec(connection, (const char*) sql.utf8());
if (PQntuples(tresult) > 0)
mDataComment = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

// Populate the field vector for this layer. The field vector contains
// field name, type, length, and precision (if numeric)
sql = "select * from " + mSchemaTableName + " limit 0";

PGresult *result = PQexec(connection, (const char *) (sql.utf8()));
//--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl;

// The queries inside this loop could possibly be combined into one
// single query - this would make the code run faster.

for (int i = 0; i < PQnfields(result); i++)
{
QString fieldName = PQfname(result, i);
int fldtyp = PQftype(result, i);
QString typOid = QString().setNum(fldtyp);
int fieldModifier = PQfmod(result, i);
QString fieldComment("");

sql = "SELECT typname, typlen FROM pg_type WHERE "
"oid = (SELECT typelem FROM pg_type WHERE "
"typelem = " + typOid + " AND typlen = -1)";

PGresult* oidResult = PQexec(connection, (const char *) sql);
QString fieldTypeName = PQgetvalue(oidResult, 0, 0);
QString fieldSize = PQgetvalue(oidResult, 0, 1);
PQclear(oidResult);

sql = "SELECT attnum FROM pg_attribute WHERE "
"attrelid = " + tableoid + " AND attname = '" + fieldName + "'";
PGresult *tresult = PQexec(connection, (const char *)(sql.utf8()));
QString attnum = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

sql = "SELECT description FROM pg_description WHERE "
"objoid = " + tableoid + " AND objsubid = " + attnum;
tresult = PQexec(connection, (const char*)(sql.utf8()));
if (PQntuples(tresult) > 0)
fieldComment = PQgetvalue(tresult, 0, 0);
PQclear(tresult);

QgsDebugMsg("Field: " + attnum + " maps to " + QString::number(i) + " " + fieldName + ", "
+ fieldTypeName + " (" + QString::number(fldtyp) + "), " + fieldSize + ", " + QString::number(fieldModifier));

if(fieldName!=geometryColumn)
{
QVariant::Type fieldType;
if (fieldTypeName.find("int") != -1 || fieldTypeName.find("serial") != -1)
fieldType = QVariant::Int;
else if (fieldTypeName == "real" || fieldTypeName == "double precision" || \
fieldTypeName.find("float") != -1)
fieldType = QVariant::Double;
else
fieldType = QVariant::String;
attributeFields.insert(i, QgsField(fieldName, fieldType, fieldTypeName, fieldSize.toInt(), fieldModifier, fieldComment));
}
}
PQclear(result);
}

QString QgsPostgresProvider::getPrimaryKey()
{
// check to see if there is an unique index on the relation, which
Expand Down
5 changes: 4 additions & 1 deletion src/providers/postgres/qgspostgresprovider.h
Expand Up @@ -180,7 +180,7 @@ class QgsPostgresProvider:public QgsVectorDataProvider
QString dataComment() const;

/** Reset the layer - for a PostgreSQL layer, this means clearing the PQresult
* pointer and setting it to 0
* pointer, setting it to 0 and reloading the field list
*/
void reset();

Expand Down Expand Up @@ -327,6 +327,9 @@ class QgsPostgresProvider:public QgsVectorDataProvider
void repaintRequested();

private:
/** Load the field list
*/
void loadFields();

bool mFirstFetch; //true if fetch forward is called the first time after select
std::vector < QgsFeature > features;
Expand Down

0 comments on commit 66d22b1

Please sign in to comment.