Skip to content
Permalink
Browse files

Extended enum support in postgres provider to work also with domain c…

…heck constrains (at the moment only for constrain types like VALUE in ('a', 'b', 'c'))

git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@10940 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent
mhugent committed Jun 17, 2009
1 parent 380173a commit 8a5581ad2e96c162a2374357996428a7b57b4742
@@ -143,6 +143,11 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
{
cb->addItem(*s_it);
}
int idx = cb->findText( myFieldValue.toString() );
if ( idx >= 0 )
{
cb->setCurrentIndex( idx );
}
myWidget = cb;
}
break;
@@ -1696,48 +1696,116 @@ void QgsPostgresProvider::enumValues( int index, QStringList& enumList )
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)
{
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)
{
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)
//try to read enum_range of attribute
if(!parseEnumRange(enumList, f_it->name()))
{
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);
}
enumList << currentEnumValue;
currentEnumValue.remove(0, 1);
}
if(currentEnumValue.endsWith("'") || currentEnumValue.endsWith("\""))
{
currentEnumValue.chop(1);
}
enumValues << currentEnumValue;
}
return true;
}
else if (typtype.compare("d", Qt::CaseInsensitive) == 0)
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. Todo: evaluate the check constraint
//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)
{
//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);
}
}
}
return true;
}
}
return false;
}

// Returns the maximum value of an attribute
@@ -345,6 +345,19 @@ class QgsPostgresProvider : public QgsVectorDataProvider
*/
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;

0 comments on commit 8a5581a

Please sign in to comment.
You can’t perform that action at this time.