[QGIS Commit] r10940 - in trunk/qgis/src: app providers/postgres

svn_qgis at osgeo.org svn_qgis at osgeo.org
Wed Jun 17 05:42:25 EDT 2009


Author: mhugent
Date: 2009-06-17 05:42:24 -0400 (Wed, 17 Jun 2009)
New Revision: 10940

Modified:
   trunk/qgis/src/app/qgsattributedialog.cpp
   trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
   trunk/qgis/src/providers/postgres/qgspostgresprovider.h
Log:
Extended enum support in postgres provider to work also with domain check constrains (at the moment only for constrain types like VALUE in ('a', 'b', 'c'))

Modified: trunk/qgis/src/app/qgsattributedialog.cpp
===================================================================
--- trunk/qgis/src/app/qgsattributedialog.cpp	2009-06-17 09:09:59 UTC (rev 10939)
+++ trunk/qgis/src/app/qgsattributedialog.cpp	2009-06-17 09:42:24 UTC (rev 10940)
@@ -143,6 +143,11 @@
         {
           cb->addItem(*s_it);
         }
+        int idx = cb->findText( myFieldValue.toString() );
+        if ( idx >= 0 )
+        {
+          cb->setCurrentIndex( idx );
+        }
         myWidget = cb;
       }
       break;

Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp	2009-06-17 09:09:59 UTC (rev 10939)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.cpp	2009-06-17 09:42:24 UTC (rev 10940)
@@ -1696,7 +1696,7 @@
     return;
   }
 
-  //is type an enum or a domain type?
+  //is type an enum?
   QString typeSql = QString("SELECT typtype FROM pg_type where typname = %1").arg(quotedValue(typeName));
   Result typeRes = connectionRO->PQexec( typeSql );
   if ( PQresultStatus( typeRes ) != PGRES_TUPLES_OK || PQntuples(typeRes) < 1)
@@ -1704,40 +1704,108 @@
     return;
   }
 
+
   QString typtype = PQgetvalue( typeRes, 0, 0 );
   if(typtype.compare("e", Qt::CaseInsensitive) == 0)
   {
-    //parse enum_range
-    QString enumRangeSql = QString("SELECT enum_range(%1) from %2 limit1").arg(quotedIdentifier(f_it.value().name())).arg(mSchemaTableName);
-    Result enumRangeRes = connectionRO->PQexec(enumRangeSql);
-    if ( PQresultStatus( enumRangeRes ) != PGRES_TUPLES_OK || PQntuples(enumRangeRes) > 0)
+    //try to read enum_range of attribute
+    if(!parseEnumRange(enumList, f_it->name()))
     {
-      QString enumRangeString = PQgetvalue(enumRangeRes, 0, 0);
-      //strip away the brackets at begin and end
-      enumRangeString.chop(1);
-      enumRangeString.remove(0, 1);
-      QStringList rangeSplit = enumRangeString.split(",");
-      QStringList::const_iterator range_it = rangeSplit.constBegin();
-      for(; range_it != rangeSplit.constEnd(); ++range_it)
+      enumList.clear();
+    }
+  }
+  else
+  {
+    //is there a domain check constraint for the attribute?
+    if(!parseDomainCheckConstraint(enumList, f_it->name()))
+    {
+       enumList.clear();
+    }
+  }
+}
+
+bool QgsPostgresProvider::parseEnumRange(QStringList& enumValues, const QString& attributeName) const
+{
+  enumValues.clear();
+  QString enumRangeSql = QString("SELECT enum_range(%1) from %2 limit1").arg(quotedIdentifier(attributeName)).arg(mSchemaTableName);
+  Result enumRangeRes = connectionRO->PQexec(enumRangeSql);
+  if ( PQresultStatus( enumRangeRes ) == PGRES_TUPLES_OK && PQntuples(enumRangeRes) > 0)
+  {
+    QString enumRangeString = PQgetvalue(enumRangeRes, 0, 0);
+    //strip away the brackets at begin and end
+    enumRangeString.chop(1);
+    enumRangeString.remove(0, 1);
+    QStringList rangeSplit = enumRangeString.split(",");
+    QStringList::const_iterator range_it = rangeSplit.constBegin();
+    for(; range_it != rangeSplit.constEnd(); ++range_it)
+    {
+      QString currentEnumValue = *range_it;
+      //remove quotes from begin and end of the value
+      if(currentEnumValue.startsWith("'") || currentEnumValue.startsWith("\""))
       {
-        QString currentEnumValue = *range_it;
-        //remove quotes from begin and end of the value
-        if(currentEnumValue.startsWith("'") || currentEnumValue.startsWith("\""))
+        currentEnumValue.remove(0, 1);
+      }
+      if(currentEnumValue.endsWith("'") || currentEnumValue.endsWith("\""))
+      {
+        currentEnumValue.chop(1);
+      }
+      enumValues << currentEnumValue;
+    }
+    return true;
+  }
+  return false;
+}
+
+bool QgsPostgresProvider::parseDomainCheckConstraint(QStringList& enumValues, const QString& attributeName) const
+{
+  enumValues.clear();
+
+  //is it a domain type with a check constraint?
+  QString domainSql = QString("SELECT domain_name from information_schema.columns where table_name = %1 and column_name = %2").arg(quotedValue(mTableName)).arg(quotedValue(attributeName));
+  Result domainResult = connectionRO->PQexec(domainSql);
+  if ( PQresultStatus( domainResult ) == PGRES_TUPLES_OK && PQntuples(domainResult) > 0)
+  {
+    //a domain type
+    QString domainCheckDefinitionSql = QString("SELECT consrc FROM pg_constraint where conname = (SELECT constraint_name FROM information_schema.domain_constraints WHERE domain_name = %1)").arg(quotedValue(PQgetvalue(domainResult, 0, 0)));
+    Result domainCheckRes = connectionRO->PQexec(domainCheckDefinitionSql);
+    if ( PQresultStatus(domainCheckRes) == PGRES_TUPLES_OK && PQntuples(domainCheckRes) > 0)
+    {
+      QString checkDefinition = PQgetvalue(domainCheckRes, 0, 0);
+
+      //we assume that the constraint is of the following form:
+      //(VALUE = ANY (ARRAY['a'::text, 'b'::text, 'c'::text, 'd'::text]))
+      //normally, postgresql creates that if the contstraint has been specified as 'VALUE in ('a', 'b', 'c', 'd')
+
+      //todo: ANY must occure before ARRAY
+      int anyPos = checkDefinition.indexOf("VALUE = ANY");
+      int arrayPosition = checkDefinition.lastIndexOf("ARRAY[");
+      int closingBracketPos = checkDefinition.indexOf("]", arrayPosition + 6);
+
+      if(anyPos == -1 || anyPos >= arrayPosition)
+      {
+        return false; //constraint has not the required format
+      }
+
+      if(arrayPosition != -1)
+      {
+        QString valueList = checkDefinition.mid(arrayPosition + 6, closingBracketPos);
+        QStringList commaSeparation = valueList.split(",", QString::SkipEmptyParts);
+        QStringList::const_iterator cIt = commaSeparation.constBegin();
+        for(; cIt != commaSeparation.constEnd(); ++cIt)
         {
-          currentEnumValue.remove(0, 1);
+          //get string between ''
+          int beginQuotePos = cIt->indexOf("'");
+          int endQuotePos = cIt->lastIndexOf("'");
+          if(beginQuotePos != -1 && (endQuotePos - beginQuotePos) > 1)
+          {
+            enumValues << cIt->mid(beginQuotePos + 1, endQuotePos - beginQuotePos - 1);
+          }
         }
-        if(currentEnumValue.endsWith("'") || currentEnumValue.endsWith("\""))
-        {
-          currentEnumValue.chop(1);
-        }
-        enumList << currentEnumValue;
       }
+      return true;
     }
   }
-  else if (typtype.compare("d", Qt::CaseInsensitive) == 0)
-  {
-    //a domain type. Todo: evaluate the check constraint
-  }
+  return false;
 }
 
 // Returns the maximum value of an attribute

Modified: trunk/qgis/src/providers/postgres/qgspostgresprovider.h
===================================================================
--- trunk/qgis/src/providers/postgres/qgspostgresprovider.h	2009-06-17 09:09:59 UTC (rev 10939)
+++ trunk/qgis/src/providers/postgres/qgspostgresprovider.h	2009-06-17 09:42:24 UTC (rev 10940)
@@ -345,6 +345,19 @@
     */
     void loadFields();
 
+    /**Parses the enum_range of an attribute and inserts the possible values into a stringlist
+    @param enumValues the stringlist where the values are appended
+    @param attributeName the name of the enum attribute
+    @return true in case of success and fals in case of error (e.g. if the type is not an enum type)*/
+    bool parseEnumRange(QStringList& enumValues, const QString& attributeName) const;
+
+    /** Parses the possible enum values of a domain type (given in the check constraint of the domain type)
+    @param enumValues Reference to list that receives enum values
+    @param attributeName Name of the domain type attribute
+    @return true in case of success and false in case of error (e.g. if the attribute is not a domain type or does not have a check constraint)
+    */
+    bool parseDomainCheckConstraint(QStringList& enumValues, const QString& attributeName) const;
+
     bool mFetching;   // true if a cursor was declared
     std::vector < QgsFeature > features;
     QgsFieldMap attributeFields;



More information about the QGIS-commit mailing list