Skip to content

Commit d5bdbb4

Browse files
author
jef
committedMar 27, 2008
More work on the postgres provider:
- put common code from select/getNextFeature and getFeatureById methods to new declareCursor and getFeature methods - unify type handling and support bool, arrays and time types (fixes #1009) - ignore columns not explicitly supported (might apply to columns previously supported implicitly; please file a bug if you run into one) - fixes a unreported problem with getFeatureById returning only NULL attributes. Please test! git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@8285 c8812cc2-4d05-0410-92ff-de0c093fc19c

File tree

2 files changed

+258
-310
lines changed

2 files changed

+258
-310
lines changed
 

‎src/providers/postgres/qgspostgresprovider.cpp

Lines changed: 247 additions & 309 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,8 @@ QgsPostgresProvider::QgsPostgresProvider(QString const & uri)
6565
: QgsVectorDataProvider(uri),
6666
geomType(QGis::WKBUnknown),
6767
mFeatureQueueSize(200),
68-
gotPostgisVersion(FALSE)
68+
gotPostgisVersion(false),
69+
mFetching(false)
6970
{
7071
// assume this is a valid layer until we determine otherwise
7172
valid = true;
@@ -366,388 +367,294 @@ QString QgsPostgresProvider::storageType() const
366367
return "PostgreSQL database with PostGIS extension";
367368
}
368369

369-
bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
370+
void QgsPostgresProvider::declareCursor(const QString &cursorName,
371+
const QgsAttributeList &fetchAttributes,
372+
bool fetchGeometry,
373+
QString whereClause,
374+
QStringList &attributeNames)
370375
{
371-
assert(mFetching);
376+
QString declare = QString("declare %1 binary cursor with hold for select %2")
377+
.arg(cursorName).arg(quotedIdentifier(primaryKey));
372378

373-
if (valid)
379+
if(fetchGeometry)
374380
{
381+
declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
382+
.arg( quotedIdentifier(geometryColumn) )
383+
.arg( endianString() );
384+
}
375385

376-
// Top up our queue if it is empty
377-
if (mFeatureQueue.empty())
386+
QgsFieldMap attributeMap = fields();
387+
for (QgsAttributeList::const_iterator it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it)
388+
{
389+
QgsFieldMap::const_iterator fieldIt = attributeMap.find(*it);
390+
if(fieldIt != attributeMap.end())
378391
{
379-
QString fetch = QString("fetch forward %1 from qgisf%2")
380-
.arg(mFeatureQueueSize)
381-
.arg(providerId);
392+
const QString &fieldname = fieldIt.value().name();
382393

383-
if(mFirstFetch)
394+
if( fieldname != primaryKey )
384395
{
385-
if(PQsendQuery(connection, fetch.toUtf8()) == 0) //fetch features in asynchronously
396+
if( fieldIt.value().typeName() == "money" || fieldIt.value().typeName().startsWith("_") )
386397
{
387-
qWarning("PQsendQuery failed (1)");
398+
// money and arrays don't support cast to text, but return text
399+
// TODO: check other types
400+
declare += "," + quotedIdentifier( fieldname );
401+
}
402+
else if( fieldIt.value().typeName() == "bool" )
403+
{
404+
// bool doesn't support cast to text either and even doesn't return text.
405+
// (even text() doesn't work with binary cursors)
406+
declare += QString(",CASE WHEN %1 THEN 't' WHEN NOT %1 THEN 'f' ELSE NULL END AS %1")
407+
.arg( quotedIdentifier(fieldname) );
408+
}
409+
else
410+
{
411+
declare += "," + quotedIdentifier( fieldname ) + "::text";
388412
}
389-
}
390-
mFirstFetch = false;
391-
queryResult = PQgetResult(connection);
392-
PQgetResult(connection); //just to get the 0 pointer...
393-
394-
int rows = PQntuples(queryResult);
395-
396-
if (rows == 0)
397-
{
398-
QgsDebugMsg("End of features");
399-
400-
PQclear(queryResult);
401-
402-
return false;
403413
}
404414

405-
for (int row = 0; row < rows; row++)
406-
{
407-
int oid = *(int *)PQgetvalue(queryResult, row, PQfnumber(queryResult,quotedIdentifier(primaryKey).toUtf8()));
415+
attributeNames << fieldname;
416+
}
417+
}
408418

409-
if (swapEndian)
410-
oid = ntohl(oid); // convert oid to opposite endian
411-
412-
mFeatureQueue.push(QgsFeature());
419+
declare += " from " + mSchemaTableName;
420+
421+
if( !whereClause.isEmpty() )
422+
declare += QString(" where %1").arg(whereClause);
413423

414-
// set ID
415-
mFeatureQueue.back().setFeatureId(oid);
424+
QgsDebugMsg("Binary cursor: " + declare);
416425

417-
// fetch attributes
418-
std::list<QString>::const_iterator name_it = mFetchAttributeNames.begin();
419-
QgsAttributeList::const_iterator index_it = mAttributesToFetch.constBegin();
426+
PQexecNR(connection, declare.toUtf8());
427+
}
420428

421-
for(; name_it != mFetchAttributeNames.end(); ++name_it, ++index_it)
422-
{
423-
QString val;
429+
void QgsPostgresProvider::getFeature(PGresult *queryResult, int row, bool fetchGeometry,
430+
QgsFeature &feature,
431+
const QStringList &attributeNames,
432+
const QgsAttributeList &fetchAttributes)
433+
{
434+
int oid = *(int *)PQgetvalue(queryResult, row, PQfnumber(queryResult,quotedIdentifier(primaryKey).toUtf8()));
435+
if (swapEndian)
436+
oid = ntohl(oid); // convert oid to opposite endian
424437

425-
if( (*name_it) == primaryKey)
426-
{
427-
val = QString::number(oid);
428-
}
429-
else
430-
{
431-
int fn = PQfnumber(queryResult,quotedIdentifier(*name_it).toUtf8());
432-
433-
if( !PQgetisnull(queryResult, row, fn) )
434-
val = QString::fromUtf8(PQgetvalue(queryResult, row, fn));
435-
else
436-
val = QString::null;
437-
}
438-
439-
if( val.isNull() )
440-
{
441-
mFeatureQueue.back().addAttribute(*index_it, val);
442-
}
443-
else
444-
{
445-
switch (attributeFields[*index_it].type())
446-
{
447-
case QVariant::LongLong:
448-
mFeatureQueue.back().addAttribute(*index_it, val.toLongLong());
449-
break;
450-
case QVariant::Int:
451-
mFeatureQueue.back().addAttribute(*index_it, val.toInt());
452-
break;
453-
case QVariant::Double:
454-
mFeatureQueue.back().addAttribute(*index_it, val.toDouble());
455-
break;
456-
case QVariant::String:
457-
mFeatureQueue.back().addAttribute(*index_it, val);
458-
break;
459-
default:
460-
assert(0 && "unsupported field type");
461-
}
462-
}
463-
}
438+
feature.setFeatureId(oid);
464439

465-
//fetch geometry
466-
if (mFetchGeom)
467-
{
468-
int returnedLength = PQgetlength(queryResult, row, PQfnumber(queryResult,"qgs_feature_geometry"));
469-
if(returnedLength > 0)
470-
{
471-
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
472-
memset(featureGeom, '\0', returnedLength + 1);
473-
memcpy(featureGeom, PQgetvalue(queryResult, row, PQfnumber(queryResult,QString("qgs_feature_geometry").toUtf8())), returnedLength);
474-
mFeatureQueue.back().setGeometryAndOwnership(featureGeom, returnedLength + 1);
475-
}
476-
else
477-
{
478-
mFeatureQueue.back().setGeometryAndOwnership(0, 0);
479-
QgsDebugMsg("Couldn't get the feature geometry in binary form");
480-
}
481-
}
482-
} // for each row in queue
440+
// fetch attributes
441+
QgsAttributeList::const_iterator it = fetchAttributes.constBegin();
442+
for(QStringList::const_iterator namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt, ++it)
443+
{
444+
QString val;
483445

484-
PQclear(queryResult);
446+
if( (*namesIt) == primaryKey)
447+
{
448+
val = QString::number(oid);
449+
}
450+
else
451+
{
452+
int fn = PQfnumber(queryResult,quotedIdentifier(*namesIt).toUtf8());
485453

486-
if(PQsendQuery(connection, fetch.toUtf8()) == 0) //already fetch the next couple of features asynchronously
454+
if( !PQgetisnull(queryResult, row, fn) )
487455
{
488-
qWarning("PQsendQuery failed (2)");
456+
val = QString::fromUtf8(PQgetvalue(queryResult, row, fn));
489457
}
458+
else
459+
{
460+
val = QString::null;
461+
}
462+
}
490463

491-
} // if new queue is required
492-
493-
// Now return the next feature from the queue
494-
if(mFetchGeom)
464+
if( val.isNull() )
495465
{
496-
QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
497-
feature.setGeometry(featureGeom);
466+
feature.addAttribute(*it, val);
498467
}
499468
else
500469
{
501-
feature.setGeometryAndOwnership(0, 0);
470+
switch (attributeFields[*it].type())
471+
{
472+
case QVariant::LongLong:
473+
feature.addAttribute(*it, val.toLongLong());
474+
break;
475+
case QVariant::Int:
476+
feature.addAttribute(*it, val.toInt());
477+
break;
478+
case QVariant::Double:
479+
feature.addAttribute(*it, val.toDouble());
480+
break;
481+
case QVariant::String:
482+
feature.addAttribute(*it, val);
483+
break;
484+
default:
485+
assert(0 && "unsupported field type");
486+
}
502487
}
503-
feature.setFeatureId(mFeatureQueue.front().featureId());
504-
feature.setAttributeMap(mFeatureQueue.front().attributeMap());
505-
506-
mFeatureQueue.pop();
507-
508-
}
509-
else
510-
{
511-
QgsDebugMsg("Read attempt on an invalid postgresql data source");
512-
return false;
513488
}
514489

515-
return true;
516-
}
517-
518-
void QgsPostgresProvider::select(QgsAttributeList fetchAttributes,
519-
QgsRect rect,
520-
bool fetchGeometry,
521-
bool useIntersect)
522-
{
523-
mFetchGeom = fetchGeometry;
524-
mAttributesToFetch = fetchAttributes;
525-
526-
mFetchAttributeNames.clear();
527-
QgsFieldMap attributeMap = fields();
528-
QgsFieldMap::const_iterator fieldIt;
529-
for(QgsAttributeList::const_iterator it = mAttributesToFetch.constBegin();
530-
it != mAttributesToFetch.constEnd(); ++it)
490+
if (fetchGeometry)
531491
{
532-
fieldIt = attributeMap.find(*it);
533-
if(fieldIt != attributeMap.end())
492+
int returnedLength = PQgetlength(queryResult, row, PQfnumber(queryResult,"qgs_feature_geometry"));
493+
if(returnedLength > 0)
534494
{
535-
mFetchAttributeNames.push_back(fieldIt.value().name());
495+
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
496+
memset(featureGeom, '\0', returnedLength + 1);
497+
memcpy(featureGeom, PQgetvalue(queryResult, row, PQfnumber(queryResult,QString("qgs_feature_geometry").toUtf8())), returnedLength);
498+
feature.setGeometryAndOwnership(featureGeom, returnedLength + 1);
536499
}
537-
}
500+
else
501+
{
502+
feature.setGeometryAndOwnership(0, 0);
503+
QgsDebugMsg("Couldn't get the feature geometry in binary form");
504+
}
505+
}
506+
}
538507

508+
void QgsPostgresProvider::select(QgsAttributeList fetchAttributes, QgsRect rect, bool fetchGeometry, bool useIntersect)
509+
{
510+
QString cursorName = QString("qgisf%1").arg(providerId);
511+
539512
if(mFetching)
540513
{
541-
PQexecNR(connection, QString("CLOSE qgisf%1").arg(providerId).toUtf8() );
514+
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8() );
542515
mFetching=false;
543-
}
544-
545-
QString declare = QString("declare qgisf%1 binary cursor with hold for select %2")
546-
.arg(providerId).arg(quotedIdentifier(primaryKey));
547-
548-
if(fetchGeometry)
549-
{
550-
declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
551-
.arg( quotedIdentifier(geometryColumn) )
552-
.arg( endianString() );
553-
}
554-
555-
for(std::list<QString>::const_iterator it = mFetchAttributeNames.begin(); it != mFetchAttributeNames.end(); ++it)
556-
{
557-
if( (*it) != primaryKey) //no need to fetch primary key again
516+
517+
while(!mFeatureQueue.empty())
558518
{
559-
declare += "," + quotedIdentifier(*it) + "::text";
519+
mFeatureQueue.pop();
560520
}
561521
}
562522

563-
declare += QString(" from %1").arg(mSchemaTableName);
564-
565-
QgsDebugMsg("Binary cursor: " + declare);
566-
567-
bool hasWhere = FALSE;
523+
QString whereClause;
568524

569525
if(!rect.isEmpty())
570526
{
571527
if(useIntersect)
572528
{
573529
// Contributed by #qgis irc "creeping"
574530
// This version actually invokes PostGIS's use of spatial indexes
575-
declare += " where " + quotedIdentifier(geometryColumn);
576-
declare += " && setsrid('BOX3D(" + rect.asWKTCoords();
577-
declare += ")'::box3d,";
578-
declare += srid;
579-
declare += ")";
580-
declare += " and intersects(" + quotedIdentifier(geometryColumn);
581-
declare += ", setsrid('BOX3D(" + rect.asWKTCoords();
582-
declare += ")'::box3d,";
583-
declare += srid;
584-
declare += "))";
531+
whereClause = QString("%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))")
532+
.arg( quotedIdentifier(geometryColumn) )
533+
.arg( rect.asWKTCoords() )
534+
.arg( srid );
585535
}
586536
else
587537
{
588-
declare += " where " + quotedIdentifier(geometryColumn);
589-
declare += " && setsrid('BOX3D(" + rect.asWKTCoords();
590-
declare += ")'::box3d,";
591-
declare += srid;
592-
declare += ")";
538+
whereClause = QString("%1 && setsrid('BOX3D(%2)'::box3d,%3)")
539+
.arg( quotedIdentifier(geometryColumn) )
540+
.arg( rect.asWKTCoords() )
541+
.arg( srid );
593542
}
594-
hasWhere = TRUE;
595543
}
596544

597-
if(sqlWhereClause.length() > 0)
545+
if( !sqlWhereClause.isEmpty() )
598546
{
599-
if (hasWhere)
600-
declare += " and ";
601-
else
602-
declare += " where ";
603-
declare += "(" + sqlWhereClause + ")";
604-
hasWhere = TRUE;
605-
}
547+
if (!whereClause.isEmpty())
548+
whereClause += " and ";
606549

607-
QgsDebugMsg("Selecting features using: " + declare);
608-
609-
PQexecNR(connection, declare.toUtf8());
610-
611-
while(!mFeatureQueue.empty())
612-
{
613-
mFeatureQueue.pop();
550+
whereClause += "(" + sqlWhereClause + ")";
614551
}
615552

553+
mFetchGeom = fetchGeometry;
554+
mAttributesToFetch = fetchAttributes;
555+
declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause, mFetchAttributeNames );
556+
616557
mFetching = true;
617558
mFirstFetch = true;
618559
}
619560

620-
bool QgsPostgresProvider::getFeatureAtId(int featureId,
621-
QgsFeature& feature,
622-
bool fetchGeometry,
623-
QgsAttributeList fetchAttributes)
561+
bool QgsPostgresProvider::getNextFeature(QgsFeature& feature)
624562
{
625-
std::list<QString> attributeNames;
626-
QgsFieldMap fldMap = fields();
627-
QgsFieldMap::const_iterator fieldIt;
628-
QgsAttributeList::const_iterator it;
629-
std::list<QString>::const_iterator namesIt;
563+
QString cursorName = QString("qgisf%1").arg(providerId);
630564

631-
for (it = fetchAttributes.constBegin(); it != fetchAttributes.constEnd(); ++it)
565+
if (!valid)
632566
{
633-
fieldIt = fldMap.find(*it);
634-
if(fieldIt != fldMap.end())
635-
{
636-
attributeNames.push_back(fieldIt.value().name());
637-
}
567+
QgsDebugMsg("Read attempt on an invalid postgresql data source");
568+
return false;
638569
}
639570

640-
QString declare = QString("declare qgisfid%1 binary cursor with hold for select %2")
641-
.arg(providerId).arg(quotedIdentifier(primaryKey));
642-
643-
if(fetchGeometry)
571+
// Top up our queue if it is empty
572+
if (mFeatureQueue.empty())
644573
{
645-
declare += QString(",asbinary(%1,'%2') as qgs_feature_geometry")
646-
.arg( quotedIdentifier(geometryColumn) )
647-
.arg( endianString() );
648-
}
574+
QString fetch = QString("fetch forward %1 from %2").arg(mFeatureQueueSize).arg(cursorName);
575+
if(mFirstFetch)
576+
{
577+
if(PQsendQuery(connection, fetch.toUtf8()) == 0) //fetch features in asynchronously
578+
{
579+
qWarning("PQsendQuery failed (1)");
580+
}
581+
}
582+
mFirstFetch = false;
583+
queryResult = PQgetResult(connection);
584+
PQgetResult(connection); //just to get the 0 pointer...
649585

650-
for(namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt)
651-
{
652-
if( (*namesIt) != primaryKey) //no need to fetch primary key again
586+
int rows = PQntuples(queryResult);
587+
if (rows == 0)
653588
{
654-
declare += "," + quotedIdentifier(*namesIt) + "::text";
589+
QgsDebugMsg("End of features");
590+
PQclear(queryResult);
591+
return false;
655592
}
656-
}
657593

658-
declare += QString(" from %1 where %2=%3")
659-
.arg(mSchemaTableName)
660-
.arg(quotedIdentifier(primaryKey))
661-
.arg(featureId);
594+
for (int row = 0; row < rows; row++)
595+
{
596+
mFeatureQueue.push(QgsFeature());
597+
getFeature(queryResult, row, mFetchGeom, mFeatureQueue.back(), mFetchAttributeNames, mAttributesToFetch);
598+
} // for each row in queue
662599

663-
QgsDebugMsg("Selecting feature using: " + declare);
600+
PQclear(queryResult);
664601

665-
// execute query
666-
PQexecNR(connection, declare.toUtf8());
667-
668-
PGresult *res = PQexec(connection, QString("fetch forward 1 from qgisfid%1").arg(providerId).toUtf8());
602+
if(PQsendQuery(connection, fetch.toUtf8()) == 0) //already fetch the next couple of features asynchronously
603+
{
604+
qWarning("PQsendQuery failed (2)");
605+
}
606+
} // if new queue is required
669607

670-
int rows = PQntuples(res);
671-
if (rows == 0)
608+
// Now return the next feature from the queue
609+
if(mFetchGeom)
672610
{
673-
PQclear(res);
674-
PQexecNR(connection, QString("CLOSE qgisfid%1").arg(providerId).toUtf8());
675-
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
676-
return FALSE;
611+
QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership();
612+
feature.setGeometry(featureGeom);
677613
}
614+
else
615+
{
616+
feature.setGeometryAndOwnership(0, 0);
617+
}
618+
feature.setFeatureId(mFeatureQueue.front().featureId());
619+
feature.setAttributeMap(mFeatureQueue.front().attributeMap());
678620

679-
// set ID
680-
int oid = *(int *)PQgetvalue(res, 0, PQfnumber(res,quotedIdentifier(primaryKey).toUtf8()));
681-
if (swapEndian)
682-
oid = ntohl(oid); // convert oid to opposite endian
683-
feature.setFeatureId(oid);
684-
685-
// fetch attributes
686-
it = fetchAttributes.constBegin();
621+
mFeatureQueue.pop();
687622

688-
for(namesIt = attributeNames.begin(); namesIt != attributeNames.end(); ++namesIt, ++it)
689-
{
690-
QString val;
623+
return true;
624+
}
691625

692-
if( (*namesIt) == primaryKey)
693-
{
694-
val = QString::number(oid);
695-
}
696-
else
697-
{
698-
int fn = PQfnumber(res,quotedIdentifier(*namesIt).toUtf8());
626+
bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, bool fetchGeometry, QgsAttributeList fetchAttributes)
627+
{
628+
QStringList attributeNames;
629+
QString cursorName = QString("qgisfid%1").arg(providerId);
630+
declareCursor( cursorName, fetchAttributes, fetchGeometry, QString("%2=%3").arg(quotedIdentifier(primaryKey)).arg(featureId), attributeNames );
699631

700-
if( PQgetisnull(res, 0, fn) )
701-
val = QString::fromUtf8(PQgetvalue(res, 0, fn));
702-
else
703-
val = QString::null;
704-
}
632+
PGresult *queryResult = PQexec(connection, QString("fetch forward 1 from %1").arg(cursorName).toUtf8());
633+
if(queryResult==0)
634+
return false;
705635

706-
if( val.isNull() )
707-
{
708-
feature.addAttribute(*it, val);
709-
}
710-
else
711-
{
712-
switch (attributeFields[*it].type())
713-
{
714-
case QVariant::LongLong:
715-
feature.addAttribute(*it, val.toLongLong());
716-
break;
717-
case QVariant::Int:
718-
feature.addAttribute(*it, val.toInt());
719-
break;
720-
case QVariant::Double:
721-
feature.addAttribute(*it, val.toDouble());
722-
break;
723-
case QVariant::String:
724-
feature.addAttribute(*it, val);
725-
break;
726-
default:
727-
assert(0 && "unsupported field type");
728-
}
729-
}
636+
int rows = PQntuples(queryResult);
637+
if (rows == 0)
638+
{
639+
QgsDebugMsg("feature " + QString::number(featureId) + " not found");
640+
PQclear(queryResult);
641+
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8());
642+
return false;
730643
}
731-
732-
// fetch geometry
733-
if (fetchGeometry)
644+
else if(rows != 1)
734645
{
735-
int returnedLength = PQgetlength(res, 0, PQfnumber(res,"qgs_feature_geometry"));
736-
if(returnedLength > 0)
737-
{
738-
unsigned char *featureGeom = new unsigned char[returnedLength + 1];
739-
memset(featureGeom, '\0', returnedLength + 1);
740-
memcpy(featureGeom, PQgetvalue(res, 0, PQfnumber(res,QString("qgs_feature_geometry").toUtf8())), returnedLength);
741-
feature.setGeometryAndOwnership(featureGeom, returnedLength + 1);
742-
}
646+
QgsDebugMsg( QString("found %1 features instead of just one.").arg(rows) );
743647
}
744648

745-
PQclear(res);
746-
PQexecNR(connection, QString("CLOSE qgisfid%1").arg(providerId).toUtf8());
649+
getFeature(queryResult, 0, fetchGeometry, feature, attributeNames, fetchAttributes);
650+
651+
PQclear(queryResult);
747652

748-
return TRUE;
653+
PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8());
654+
return true;
749655
}
750656

657+
751658
QgsDataSourceURI& QgsPostgresProvider::getURI()
752659
{
753660
return mUri;
@@ -891,16 +798,38 @@ void QgsPostgresProvider::loadFields()
891798
if(fieldName!=geometryColumn)
892799
{
893800
QVariant::Type fieldType;
894-
if (fieldTypeName.find("int8") != -1)
801+
bool isArray = fieldTypeName.startsWith("_");
802+
803+
if(isArray)
804+
fieldTypeName = fieldTypeName.mid(1);
805+
806+
if (fieldTypeName == "int8" )
895807
fieldType = QVariant::LongLong;
896-
else if (fieldTypeName.find("int") != -1 || fieldTypeName.find("serial") != -1)
808+
else if (fieldTypeName.startsWith("int") || fieldTypeName=="serial" )
897809
fieldType = QVariant::Int;
898-
else if (fieldTypeName == "real" || fieldTypeName == "double precision" || fieldTypeName.find("float") != -1)
810+
else if (fieldTypeName == "real" || fieldTypeName == "double precision" || fieldTypeName.startsWith("float") || fieldTypeName == "numeric" )
899811
fieldType = QVariant::Double;
900-
else if (fieldTypeName == "bytea")
901-
continue;
812+
else if (fieldTypeName == "text" ||
813+
fieldTypeName == "char" ||
814+
fieldTypeName == "bpchar" ||
815+
fieldTypeName == "varchar" ||
816+
fieldTypeName == "bool" ||
817+
fieldTypeName == "money" ||
818+
fieldTypeName.startsWith("time") ||
819+
fieldTypeName.startsWith("date") )
820+
fieldType = QVariant::String;
902821
else
822+
{
823+
QgsDebugMsg( "Field " + fieldName + " ignored, because of unsupported type " + fieldTypeName);
824+
continue;
825+
}
826+
827+
if(isArray)
828+
{
829+
fieldTypeName = "_" + fieldTypeName;
903830
fieldType = QVariant::String;
831+
}
832+
904833
attributeFields.insert(i, QgsField(fieldName, fieldType, fieldTypeName, fieldSize.toInt(), fieldModifier, fieldComment));
905834
}
906835
}
@@ -1653,11 +1582,16 @@ QVariant QgsPostgresProvider::minValue(int index)
16531582
QString sql;
16541583
if(sqlWhereClause.isEmpty())
16551584
{
1656-
sql = QString("select min(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName);
1585+
sql = QString("select min(%1) from %2")
1586+
.arg(quotedIdentifier(fld.name()))
1587+
.arg(mSchemaTableName);
16571588
}
16581589
else
16591590
{
1660-
sql = QString("select min(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName)+" where "+sqlWhereClause;
1591+
sql = QString("select min(%1) from %2 where %3")
1592+
.arg(quotedIdentifier(fld.name()))
1593+
.arg(mSchemaTableName)
1594+
.arg(sqlWhereClause);
16611595
}
16621596
PGresult *rmin = PQexec(connection, sql.toUtf8());
16631597
QString minValue = QString::fromUtf8(PQgetvalue(rmin,0,0));
@@ -1705,11 +1639,16 @@ QVariant QgsPostgresProvider::maxValue(int index)
17051639
QString sql;
17061640
if(sqlWhereClause.isEmpty())
17071641
{
1708-
sql = QString("select max(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName);
1642+
sql = QString("select max(%1) from %2")
1643+
.arg(quotedIdentifier(fld.name()))
1644+
.arg(mSchemaTableName);
17091645
}
17101646
else
17111647
{
1712-
sql = QString("select max(%1) from %2").arg(quotedIdentifier(fld.name())).arg(mSchemaTableName)+" where "+sqlWhereClause;
1648+
sql = QString("select max(%1) from %2 where %3")
1649+
.arg(quotedIdentifier(fld.name()))
1650+
.arg(mSchemaTableName)
1651+
.arg(sqlWhereClause);
17131652
}
17141653
PGresult *rmax = PQexec(connection, sql.toUtf8());
17151654
QString maxValue = QString::fromUtf8(PQgetvalue(rmax,0,0));
@@ -1818,7 +1757,7 @@ QString QgsPostgresProvider::postgisVersion(PGconn *connection)
18181757

18191758
useWkbHex = postgisVersionMajor < 1;
18201759

1821-
gotPostgisVersion = TRUE;
1760+
gotPostgisVersion = true;
18221761

18231762
return postgisVersionInfo;
18241763
}
@@ -1872,7 +1811,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
18721811
// e.g. for defaults
18731812
for(QgsAttributeMap::const_iterator it = attributevec.begin(); it != attributevec.end(); it++)
18741813
{
1875-
QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
1814+
QgsFieldMap::const_iterator fit = attributeFields.find( it.key() );
18761815
if (fit == attributeFields.end() )
18771816
continue;
18781817

@@ -1897,7 +1836,7 @@ bool QgsPostgresProvider::addFeatures(QgsFeatureList & flist)
18971836
}
18981837

18991838
insert += "," + quotedIdentifier(fieldname);
1900-
1839+
19011840
QString defVal = getDefaultValue( it.key() ).toString();
19021841

19031842
if( i==flist.size() )
@@ -2685,8 +2624,7 @@ void QgsPostgresProvider::PQexecNR(PGconn *conn, const char *query)
26852624
}
26862625
}
26872626

2688-
void QgsPostgresProvider::showMessageBox(const QString& title,
2689-
const QString& text)
2627+
void QgsPostgresProvider::showMessageBox(const QString& title, const QString& text)
26902628
{
26912629
QgsMessageOutput* message = QgsMessageOutput::createMessageOutput();
26922630
message->setTitle(title);

‎src/providers/postgres/qgspostgresprovider.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,16 @@ class QgsPostgresProvider:public QgsVectorDataProvider
110110
bool fetchGeometry = true,
111111
QgsAttributeList fetchAttributes = QgsAttributeList());
112112

113+
void declareCursor(const QString &cursorName,
114+
const QgsAttributeList &fetchAttributes,
115+
bool fetchGeometry,
116+
QString whereClause,
117+
QStringList &attributeNames);
118+
119+
void getFeature(PGresult *queryResult, int row, bool fetchGeometry,
120+
QgsFeature &feature,
121+
const QStringList &attributeNames,
122+
const QgsAttributeList &fetchAttributes);
113123

114124
/** Get the feature type. This corresponds to
115125
* WKBPoint,
@@ -444,7 +454,7 @@ class QgsPostgresProvider:public QgsVectorDataProvider
444454
bool swapEndian;
445455

446456
/**Stores the names of the attributes to fetch*/
447-
std::list<QString> mFetchAttributeNames;
457+
QStringList mFetchAttributeNames;
448458

449459
bool deduceEndian();
450460
bool getGeometryDetails();

0 commit comments

Comments
 (0)
Please sign in to comment.