[QGIS Commit] r8217 - in trunk/qgis/src: app providers/postgres
svn_qgis at osgeo.org
svn_qgis at osgeo.org
Thu Mar 13 14:43:36 EDT 2008
Author: jef
Date: 2008-03-13 14:43:35 -0400 (Thu, 13 Mar 2008)
New Revision: 8217
Modified:
trunk/qgis/src/app/qgsattributedialog.cpp
trunk/qgis/src/app/qgsattributetable.cpp
trunk/qgis/src/app/qgsmaptoolidentify.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
trunk/qgis/src/providers/postgres/qgspostgresprovider.h
Log:
- Support NULL database values (fixes #987 and #988)
- check for NULL values on load
- show "NULL" in attribute table and identify results
- support entry of "NULL" in attribute table or dialog
- free result of PQexec in postgres provider (fixes memory leaks)
Modified: trunk/qgis/src/app/qgsattributedialog.cpp
===================================================================
--- trunk/qgis/src/app/qgsattributedialog.cpp 2008-03-13 13:11:53 UTC (rev 8216)
+++ trunk/qgis/src/app/qgsattributedialog.cpp 2008-03-13 18:43:35 UTC (rev 8217)
@@ -67,7 +67,11 @@
QString QgsAttributeDialog::value(int row)
{
- return mTable->item(row,1)->text();
+ QString val = mTable->item(row,1)->text();
+ if(val=="NULL")
+ return QString::null;
+ else
+ return mTable->item(row,1)->text();
}
bool QgsAttributeDialog::isDirty(int row)
Modified: trunk/qgis/src/app/qgsattributetable.cpp
===================================================================
--- trunk/qgis/src/app/qgsattributetable.cpp 2008-03-13 13:11:53 UTC (rev 8216)
+++ trunk/qgis/src/app/qgsattributetable.cpp 2008-03-13 18:43:35 UTC (rev 8217)
@@ -461,7 +461,10 @@
fieldIndex = provider->indexFromFieldName(record_it.key());
if(fieldIndex != -1)
{
- newAttMap.insert(fieldIndex, record_it.value());
+ if( record_it.value()=="NULL" )
+ newAttMap.insert(fieldIndex, QVariant(QString::null) );
+ else
+ newAttMap.insert(fieldIndex, record_it.value());
}
else
{
@@ -572,7 +575,7 @@
for (it = attr.begin(); it != attr.end(); ++it)
{
// get the field values
- setText(row, h++, it->toString());
+ setText(row, h++, it->isNull() ? "NULL" : it->toString());
}
}
Modified: trunk/qgis/src/app/qgsmaptoolidentify.cpp
===================================================================
--- trunk/qgis/src/app/qgsmaptoolidentify.cpp 2008-03-13 13:11:53 UTC (rev 8216)
+++ trunk/qgis/src/app/qgsmaptoolidentify.cpp 2008-03-13 18:43:35 UTC (rev 8217)
@@ -303,7 +303,7 @@
{
featureNode->setText(1, it->toString());
}
- mResults->addAttribute(featureNode, fields[it.key()].name(), it->toString());
+ mResults->addAttribute(featureNode, fields[it.key()].name(), it->isNull() ? "NULL" : it->toString());
}
// Calculate derived attributes and insert:
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-13 13:11:53 UTC (rev 8216)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp 2008-03-13 18:43:35 UTC (rev 8217)
@@ -207,7 +207,7 @@
// Set the postgresql message level so that we don't get the
// 'there is no transaction in progress' warning.
#ifndef QGISDEBUG
- PQexec(connection, QString("set client_min_messages to error").toUtf8());
+ PQexecNR(connection, QString("set client_min_messages to error").toUtf8());
#endif
// Kick off the long running threads
@@ -369,7 +369,7 @@
PQclear(queryResult);
if (ready)
- PQexec(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("end work").toUtf8());
ready = false;
return false;
}
@@ -393,17 +393,29 @@
for(; name_it != mFetchAttributeNames.end(); ++name_it, ++index_it)
{
QString val;
+
if( (*name_it) == primaryKey)
{
val = QString::number(oid);
}
else
{
- val = QString::fromUtf8(PQgetvalue(queryResult, row, PQfnumber(queryResult,quotedIdentifier(*name_it).toUtf8())));
+ int fn = PQfnumber(queryResult,quotedIdentifier(*name_it).toUtf8());
+
+ if( !PQgetisnull(queryResult, row, fn) )
+ val = QString::fromUtf8(PQgetvalue(queryResult, row, fn));
+ else
+ val = QString::null;
}
- switch (attributeFields[*index_it].type())
+ if( val.isNull() )
{
+ mFeatureQueue.back().addAttribute(*index_it, val);
+ }
+ else
+ {
+ switch (attributeFields[*index_it].type())
+ {
case QVariant::LongLong:
mFeatureQueue.back().addAttribute(*index_it, val.toLongLong());
break;
@@ -418,6 +430,7 @@
break;
default:
assert(0 && "unsupported field type");
+ }
}
}
@@ -559,11 +572,11 @@
// set up the cursor
if(ready){
- PQexec(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("end work").toUtf8());
}
- PQexec(connection,QString("begin work").toUtf8());
+ PQexecNR(connection,QString("begin work").toUtf8());
ready = true;
- PQexec(connection, declare.toUtf8());
+ PQexecNR(connection, declare.toUtf8());
while(!mFeatureQueue.empty())
{
@@ -614,10 +627,10 @@
QgsDebugMsg("Selecting feature using: " + sql);
- PQexec(connection,QString("begin work").toUtf8());
+ PQexecNR(connection,QString("begin work").toUtf8());
// execute query
- PQexec(connection, sql.toUtf8());
+ PQexecNR(connection, sql.toUtf8());
PGresult *res = PQexec(connection, QString("fetch forward 1 from qgisfid").toUtf8());
@@ -625,7 +638,7 @@
if (rows == 0)
{
PQclear(res);
- PQexec(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("end work").toUtf8());
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
return FALSE;
}
@@ -642,17 +655,29 @@
for(namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt, ++it)
{
QString val;
+
if( (*namesIt) == primaryKey)
{
val = QString::number(oid);
}
else
{
- val = QString::fromUtf8(PQgetvalue(res, 0, PQfnumber(res,quotedIdentifier(*namesIt).toUtf8())));
+ int fn = PQfnumber(res,quotedIdentifier(*namesIt).toUtf8());
+
+ if( PQgetisnull(res, 0, fn) )
+ val = QString::fromUtf8(PQgetvalue(res, 0, fn));
+ else
+ val = QString::null;
}
- switch (attributeFields[*it].type())
+ if( val.isNull() )
{
+ feature.addAttribute(*it, val);
+ }
+ else
+ {
+ switch (attributeFields[*it].type())
+ {
case QVariant::LongLong:
feature.addAttribute(*it, val.toLongLong());
break;
@@ -667,6 +692,7 @@
break;
default:
assert(0 && "unsupported field type");
+ }
}
}
@@ -684,7 +710,7 @@
}
PQclear(res);
- PQexec(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("end work").toUtf8());
return TRUE;
}
@@ -745,7 +771,7 @@
void QgsPostgresProvider::reset()
{
QString move = "move 0 in qgisf"; //move cursor to first record
- PQexec(connection, move.toUtf8());
+ PQexecNR(connection, move.toUtf8());
mFeatureQueue.empty();
loadFields();
}
@@ -1660,20 +1686,22 @@
QString fieldName = attributeFields[fieldId].name();
- QString sql("SELECT column_default FROM "
- "information_schema.columns WHERE "
- "column_default IS NOT NULL AND "
- "table_schema = '" + mSchemaName + "' AND "
- "table_name = '" + mTableName + "' AND "
- "column_name = '" + fieldName + "'");
+ QString sql("SELECT column_default FROM"
+ " information_schema.columns WHERE"
+ " column_default IS NOT NULL"
+ " AND table_schema = " + quotedValue(mSchemaName) +
+ " AND table_name = " + quotedValue(mTableName) +
+ " AND column_name = " + quotedValue(fieldName) );
- QString defaultValue("");
+ QVariant defaultValue = QString::null;
PGresult* result = PQexec(connection, sql.toUtf8());
- if (PQntuples(result) == 1)
+ if (PQntuples(result)==1 && !PQgetisnull(result, 0, 0) )
defaultValue = QString::fromUtf8(PQgetvalue(result, 0, 0));
+ QgsDebugMsg( QString("defaultValue for %1 is NULL: %2").arg(fieldId).arg( defaultValue.isNull() ) );
+
PQclear(result);
return defaultValue;
@@ -1735,14 +1763,20 @@
QByteArray QgsPostgresProvider::paramValue(QString fieldValue, const QString &defaultValue) const
{
- if( fieldValue=="NULL" )
- return 0;
+ if( fieldValue.isNull() )
+ return QByteArray(0); // QByteArray(0).isNull() is true
- if( fieldValue==defaultValue && !defaultValue.isEmpty() )
+ if( fieldValue==defaultValue && !defaultValue.isNull() )
{
PGresult *result = PQexec( connection, QString("select %1").arg(defaultValue).toUtf8() );
- fieldValue = QString::fromUtf8(PQgetvalue(result,0,0));
- PQclear(result);
+ if( PQgetisnull(result, 0, 0) ) {
+ PQclear(result);
+ return QByteArray(0); // QByteArray(0).isNull() is true
+ } else {
+ QString val = QString::fromUtf8(PQgetvalue(result,0,0));
+ PQclear(result);
+ return val.toUtf8();
+ }
}
return fieldValue.toUtf8();
@@ -1756,7 +1790,7 @@
bool returnvalue=true;
try {
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
// Prepare the INSERT statement
QString insert = QString("INSERT INTO %1(%2,%3")
@@ -1784,11 +1818,9 @@
QgsDebugMsg("Checking field against: " + fieldname);
- if( fieldname.isEmpty() || fieldname==geometryColumn || fieldname==primaryKey || it->isNull() )
+ if( fieldname.isEmpty() || fieldname==geometryColumn || fieldname==primaryKey )
continue;
- QString fieldvalue = it->toString();
-
int i;
for(i=1; i<flist.size(); i++)
{
@@ -1798,7 +1830,7 @@
if( thisit == attributevec.end() )
break;
- if( thisit->toString() != fieldvalue )
+ if( *thisit!=*it )
break;
}
@@ -1808,13 +1840,13 @@
if( i==flist.size() )
{
- if( fieldvalue=="NULL" || (fieldvalue==defVal && !defVal.isEmpty()) )
+ if( !defVal.isNull() && *it==defVal) {
{
- values += "," + fieldvalue;
+ values += "," + defVal;
}
else
{
- values += "," + quotedValue(fieldvalue);
+ values += "," + quotedValue( it->toString() );
}
}
else
@@ -1832,6 +1864,8 @@
if(stmt==0 || PQresultStatus(stmt)==PGRES_FATAL_ERROR)
throw PGException(stmt);
+ PQclear(stmt);
+
int primaryKeyHighWater = maxPrimaryKeyValue();
const char **param = new const char *[ fieldId.size()+2 ];
@@ -1853,13 +1887,15 @@
for(int i=0; i<fieldId.size(); i++)
{
qparam.append( paramValue( attributevec[ fieldId[i] ].toString(), defaultValue[i] ) );
- param[i+2] = qparam[i+2];
+ if( qparam[i+2].isNull() )
+ param[i+2] = 0;
+ else
+ param[i+2] = qparam[i+2];
}
PGresult *result = PQexecPrepared(connection, "addfeatures", fieldId.size()+2, param, NULL, NULL, 0);
if( result==0 || PQresultStatus(result)==PGRES_FATAL_ERROR )
{
- PQclear(stmt);
delete param;
throw PGException(result);
}
@@ -1867,13 +1903,14 @@
PQclear(result);
}
- PQclear(stmt);
+ PQexecNR(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8());
delete param;
-
- PQexec(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while adding features") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
+
+ PQexecNR(connection,QString("DEALLOCATE addfeatures").toUtf8());
returnvalue = false;
}
@@ -1886,7 +1923,7 @@
bool returnvalue=true;
try {
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
for(QgsFeatureIds::const_iterator it=id.begin();it!=id.end();++it) {
QString sql("DELETE FROM "+mSchemaTableName+" WHERE "+quotedIdentifier(primaryKey)+"="+QString::number(*it));
@@ -1900,10 +1937,10 @@
PQclear(result);
}
- PQexec(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while deleting features") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
returnvalue = false;
}
reset();
@@ -1915,7 +1952,7 @@
bool returnvalue=true;
try {
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
for(QgsNewAttributesMap::const_iterator iter=name.begin();iter!=name.end();++iter)
{
@@ -1930,10 +1967,10 @@
PQclear(result);
}
- PQexec(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while adding attributes") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
returnvalue = false;
}
@@ -1946,7 +1983,7 @@
bool returnvalue=true;
try {
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
for(QgsAttributeIds::const_iterator iter=ids.begin();iter != ids.end();++iter)
{
@@ -1967,10 +2004,10 @@
attributeFields.remove(*iter);
}
- PQexec(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while deleting attributes") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
returnvalue = false;
}
@@ -1983,7 +2020,7 @@
bool returnvalue=true;
try {
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
// cycle through the features
for(QgsChangedAttributesMap::const_iterator iter=attr_map.begin();iter!=attr_map.end();++iter)
@@ -2016,10 +2053,10 @@
}
}
- PQexec(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while changing attributes") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
returnvalue = false;
}
@@ -2048,7 +2085,7 @@
try {
// Start the PostGIS transaction
- PQexec(connection,QString("BEGIN").toUtf8());
+ PQexecNR(connection,QString("BEGIN").toUtf8());
for(QgsGeometryMap::iterator iter = geometry_map.begin();
iter != geometry_map.end();
@@ -2080,10 +2117,10 @@
} // if (*iter)
} // for each feature
- PQexec(connection,QString("COMMIT").toUtf8());
+ PQexecNR(connection,QString("COMMIT").toUtf8());
} catch(PGException &e) {
e.showErrorMessage( tr("Error while changing attributes") );
- PQexec(connection,QString("ROLLBACK").toUtf8());
+ PQexecNR(connection,QString("ROLLBACK").toUtf8());
returnvalue = false;
}
@@ -2364,16 +2401,16 @@
// get the same value using a binary cursor
- PQexec(connection,QString("begin work").toUtf8());
+ PQexecNR(connection,QString("begin work").toUtf8());
QString oidDeclare = "declare oidcursor binary cursor for select regclass('" + mSchemaTableName + "')::oid";
// set up the cursor
- PQexec(connection, oidDeclare.toUtf8());
+ PQexecNR(connection, oidDeclare.toUtf8());
QString fetch = "fetch forward 1 from oidcursor";
QgsDebugMsg("Fetching a record and attempting to get check endian-ness");
PGresult *fResult = PQexec(connection, fetch.toUtf8());
- PQexec(connection, QString("end work").toUtf8());
+ PQexecNR(connection, QString("end work").toUtf8());
swapEndian = true;
if(PQntuples(fResult) > 0){
// get the oid value from the binary cursor
@@ -2548,11 +2585,32 @@
QString QgsPostgresProvider::quotedValue( QString value )
{
+ if( value.isNull() )
+ return "NULL";
+
// FIXME: use PQescapeStringConn
value.replace("'", "''");
return value.prepend("'").append("'");
}
+void QgsPostgresProvider::PQexecNR(PGconn *conn, const char *query)
+{
+ PGresult *res = PQexec(conn, query);
+ if(res)
+ {
+ QgsDebugMsg( QString("Query: %1 returned %2 [%3]")
+ .arg(query)
+ .arg(PQresStatus(PQresultStatus(res)))
+ .arg(PQresultErrorMessage(res))
+ );
+ PQclear(res);
+ }
+ else
+ {
+ QgsDebugMsg( QString("Query: %1 returned no result buffer").arg(query) );
+ }
+}
+
void QgsPostgresProvider::showMessageBox(const QString& title,
const QString& text)
{
Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-13 13:11:53 UTC (rev 8216)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h 2008-03-13 18:43:35 UTC (rev 8217)
@@ -595,6 +595,9 @@
void appendGeomString(QgsGeometry *geom, QString &geomParam) const;
QByteArray paramValue(QString fieldvalue, const QString &defaultValue) const;
+
+ // run a query and free result buffer
+ static void PQexecNR(PGconn *conn, const char *query);
};
#endif
More information about the QGIS-commit
mailing list