bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect; bool geometryTypeFilter = mSource->mOgrGeometryTypeFilter != wkbUnknown; if ( mFetchGeometry || useIntersect || geometryTypeFilter ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { if ( mGeometrySimplifier ) mGeometrySimplifier->simplifyGeometry( geom ); // get the wkb representation int memorySize = OGR_G_WkbSize( geom ); unsigned char *wkb = new unsigned char[memorySize]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); QgsGeometry* geometry = feature.geometry(); if ( !geometry ) feature.setGeometryAndOwnership( wkb, memorySize ); else geometry->fromWkb( wkb, memorySize ); } if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) ) || ( geometryTypeFilter && ( !feature.geometry() || QgsOgrProvider::ogrWkbSingleFlatten(( OGRwkbGeometryType )feature.geometry()->wkbType() ) != mSource->mOgrGeometryTypeFilter ) ) ) { OGR_F_Destroy( fet ); return false; } } if ( !mFetchGeometry ) { feature.setGeometry( 0 ); } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < mSource->mFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } return true; }
bool QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( P->fields().count() ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups bool fetchGeom = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); bool useIntersect = mRequest.flags() & QgsFeatureRequest::ExactIntersect; bool geometryTypeFilter = P->mOgrGeometryTypeFilter != wkbUnknown; if ( fetchGeom || useIntersect || geometryTypeFilter ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { // get the wkb representation unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) ); } if (( useIntersect && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) ) || ( geometryTypeFilter && ( !feature.geometry() || wkbFlatten(( OGRwkbGeometryType )feature.geometry()->wkbType() ) != wkbFlatten( P->mOgrGeometryTypeFilter ) ) ) ) { OGR_F_Destroy( fet ); return false; } } if ( !fetchGeom ) { feature.setGeometry( 0 ); } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } return true; }
void QgsSpatiaLiteFeatureIterator::getFeatureGeometry( sqlite3_stmt* stmt, int ic, QgsFeature& feature ) { if ( sqlite3_column_type( stmt, ic ) == SQLITE_BLOB ) { unsigned char *featureGeom = NULL; size_t geom_size = 0; const void *blob = sqlite3_column_blob( stmt, ic ); size_t blob_size = sqlite3_column_bytes( stmt, ic ); QgsSpatiaLiteProvider::convertToGeosWKB(( const unsigned char * )blob, blob_size, &featureGeom, &geom_size ); if ( featureGeom ) feature.setGeometryAndOwnership( featureGeom, geom_size ); else feature.setGeometryAndOwnership( 0, 0 ); } else { // NULL geometry feature.setGeometryAndOwnership( 0, 0 ); } }
bool QgsMssqlFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( !mQuery ) return false; if ( !mQuery->isActive() ) { QgsDebugMsg( "Read attempt on inactive query" ); return false; } if ( mQuery->next() ) { feature.initAttributes( mSource->mFields.count() ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups for ( int i = 0; i < mAttributesToFetch.count(); i++ ) { QVariant v = mQuery->value( i ); feature.setAttribute( mAttributesToFetch[i], mQuery->value( i ) ); } if ( mFidCol >= 0 ) { feature.setFeatureId( mQuery->value( mFidCol ).toLongLong() ); } if ( mGeometryCol >= 0 ) { QByteArray ar = mQuery->value( mGeometryCol ).toByteArray(); unsigned char* wkb = mParser.ParseSqlGeometry(( unsigned char* )ar.data(), ar.size() ); if ( wkb ) { feature.setGeometryAndOwnership( wkb, mParser.GetWkbLen() ); } } feature.setValid( true ); return true; } return false; }
void QgsOgrFeatureIterator::readFeature( OGRFeatureH fet, QgsFeature& feature ) { feature.setFeatureId( OGR_F_GetFID( fet ) ); feature.initAttributes( P->fields().count() ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups // fetch geometry if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { OGRGeometryH geom = OGR_F_GetGeometryRef( fet ); if ( geom ) { // get the wkb representation unsigned char *wkb = new unsigned char[OGR_G_WkbSize( geom )]; OGR_G_ExportToWkb( geom, ( OGRwkbByteOrder ) QgsApplication::endian(), wkb ); feature.setGeometryAndOwnership( wkb, OGR_G_WkbSize( geom ) ); } else { feature.setGeometry( 0 ); } } // fetch attributes if ( mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes ) { const QgsAttributeList& attrs = mRequest.subsetOfAttributes(); for ( QgsAttributeList::const_iterator it = attrs.begin(); it != attrs.end(); ++it ) { getFeatureAttribute( fet, feature, *it ); } } else { // all attributes for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) { getFeatureAttribute( fet, feature, idx ); } } }
void QgsWFSFeatureIterator::copyFeature( const QgsFeature* f, QgsFeature& feature, bool fetchGeometry ) { Q_UNUSED( fetchGeometry ); if ( !f ) { return; } //copy the geometry const QgsGeometry* geometry = f->constGeometry(); if ( geometry && fetchGeometry ) { const unsigned char *geom = geometry->asWkb(); int geomSize = geometry->wkbSize(); unsigned char* copiedGeom = new unsigned char[geomSize]; memcpy( copiedGeom, geom, geomSize ); feature.setGeometryAndOwnership( copiedGeom, geomSize ); } else { feature.setGeometry( 0 ); } //and the attributes feature.initAttributes( mSource->mFields.size() ); for ( int i = 0; i < mSource->mFields.size(); i++ ) { const QVariant &v = f->attributes().value( i ); if ( v.type() != mSource->mFields.at( i ).type() ) feature.setAttribute( i, QgsVectorDataProvider::convertValue( mSource->mFields.at( i ).type(), v.toString() ) ); else feature.setAttribute( i, v ); } //id and valid feature.setValid( true ); feature.setFeatureId( f->id() ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups }
void QgsGrassFeatureIterator::setFeatureGeometry( QgsFeature& feature, int id, int type ) { unsigned char *wkb; int wkbsize; // TODO int may be 64 bits (memcpy) if ( type & ( GV_POINTS | GV_LINES | GV_FACE ) || mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) /* points or lines */ { if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { double x, y, z; Vect_get_node_coor( mSource->mMap, id, &x, &y, &z ); Vect_reset_line( mPoints ); Vect_append_point( mPoints, x, y, z ); } else { Vect_read_line( mSource->mMap, mPoints, 0, id ); } int npoints = mPoints->n_points; if ( mSource->mLayerType == QgsGrassProvider::TOPO_NODE ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_POINTS ) { wkbsize = 1 + 4 + 2 * 8; } else if ( type & GV_LINES ) { wkbsize = 1 + 4 + 4 + npoints * 2 * 8; } else // GV_FACE { wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; } wkb = new unsigned char[wkbsize]; unsigned char *wkbp = wkb; wkbp[0] = ( unsigned char ) QgsApplication::endian(); wkbp += 1; /* WKB type */ memcpy( wkbp, &mSource->mQgisType, 4 ); wkbp += 4; /* Number of rings */ if ( type & GV_FACE ) { int nrings = 1; memcpy( wkbp, &nrings, 4 ); wkbp += 4; } /* number of points */ if ( type & ( GV_LINES | GV_FACE ) ) { QgsDebugMsg( QString( "set npoints = %1" ).arg( npoints ) ); memcpy( wkbp, &npoints, 4 ); wkbp += 4; } for ( int i = 0; i < npoints; i++ ) { memcpy( wkbp, &( mPoints->x[i] ), 8 ); memcpy( wkbp + 8, &( mPoints->y[i] ), 8 ); wkbp += 16; } } else // GV_AREA { Vect_get_area_points( mSource->mMap, id, mPoints ); int npoints = mPoints->n_points; wkbsize = 1 + 4 + 4 + 4 + npoints * 2 * 8; // size without islands wkb = new unsigned char[wkbsize]; wkb[0] = ( unsigned char ) QgsApplication::endian(); int offset = 1; /* WKB type */ memcpy( wkb + offset, &mSource->mQgisType, 4 ); offset += 4; /* Number of rings */ int nisles = Vect_get_area_num_isles( mSource->mMap, id ); int nrings = 1 + nisles; memcpy( wkb + offset, &nrings, 4 ); offset += 4; /* Outer ring */ memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } /* Isles */ for ( int i = 0; i < nisles; i++ ) { Vect_get_isle_points( mSource->mMap, Vect_get_area_isle( mSource->mMap, id, i ), mPoints ); npoints = mPoints->n_points; // add space wkbsize += 4 + npoints * 2 * 8; wkb = ( unsigned char * ) realloc( wkb, wkbsize ); memcpy( wkb + offset, &npoints, 4 ); offset += 4; for ( int i = 0; i < npoints; i++ ) { memcpy( wkb + offset, &( mPoints->x[i] ), 8 ); memcpy( wkb + offset + 8, &( mPoints->y[i] ), 8 ); offset += 16; } } } feature.setGeometryAndOwnership( wkb, wkbsize ); }
bool QgsSpatiaLiteFeatureIterator::getFeature( sqlite3_stmt *stmt, QgsFeature &feature ) { bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; int ret = sqlite3_step( stmt ); if ( ret == SQLITE_DONE ) { // there are no more rows to fetch return false; } if ( ret != SQLITE_ROW ) { // some unexpected error occurred QgsMessageLog::logMessage( QObject::tr( "SQLite error getting feature: %1" ).arg( QString::fromUtf8( sqlite3_errmsg( mHandle->handle() ) ) ), QObject::tr( "SpatiaLite" ) ); return false; } // one valid row has been fetched from the result set if ( !mFetchGeometry ) { // no geometry was required feature.setGeometryAndOwnership( 0, 0 ); } feature.initAttributes( mSource->mFields.count() ); feature.setFields( mSource->mFields ); // allow name-based attribute lookups int ic; int n_columns = sqlite3_column_count( stmt ); for ( ic = 0; ic < n_columns; ic++ ) { if ( ic == 0 ) { if ( mHasPrimaryKey ) { // first column always contains the ROWID (or the primary key) QgsFeatureId fid = sqlite3_column_int64( stmt, ic ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 3 ); feature.setFeatureId( fid ); } else { // autoincrement a row number mRowNumber++; feature.setFeatureId( mRowNumber ); } } else if ( mFetchGeometry && ic == mGeomColIdx ) { getFeatureGeometry( stmt, ic, feature ); } else { if ( subsetAttributes ) { if ( ic <= mRequest.subsetOfAttributes().size() ) { int attrIndex = mRequest.subsetOfAttributes()[ic-1]; feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) ); } } else { int attrIndex = ic - 1; feature.setAttribute( attrIndex, getFeatureAttribute( stmt, ic, mSource->mFields.at( attrIndex ).type() ) ); } } } return true; }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature ) { feature.initAttributes( mSource->mFields.count() ); int col = 0; if ( mFetchGeometry ) { int returnedLength = ::PQgetlength( queryResult.result(), row, col ); if ( returnedLength > 0 ) { unsigned char *featureGeom = new unsigned char[returnedLength + 1]; memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength ); memset( featureGeom + returnedLength, 0, 1 ); // modify 2.5D WKB types to make them compliant with OGR unsigned int wkbType; memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) ); wkbType = QgsPostgresConn::wkbTypeFromOgcWkbType( wkbType ); memcpy( featureGeom + 1, &wkbType, sizeof( wkbType ) ); // change wkb type of inner geometries if ( wkbType == QGis::WKBMultiPoint25D || wkbType == QGis::WKBMultiLineString25D || wkbType == QGis::WKBMultiPolygon25D ) { unsigned int numGeoms; memcpy( &numGeoms, featureGeom + 5, sizeof( unsigned int ) ); unsigned char *wkb = featureGeom + 9; for ( unsigned int i = 0; i < numGeoms; ++i ) { unsigned int localType; memcpy( &localType, wkb + 1, sizeof( localType ) ); localType = QgsPostgresConn::wkbTypeFromOgcWkbType( localType ); memcpy( wkb + 1, &localType, sizeof( localType ) ); // skip endian and type info wkb += sizeof( unsigned int ) + 1; // skip coordinates switch ( wkbType ) { case QGis::WKBMultiPoint25D: wkb += sizeof( double ) * 3; break; case QGis::WKBMultiLineString25D: { unsigned int nPoints; memcpy( &nPoints, wkb, sizeof( int ) ); wkb += sizeof( int ) + sizeof( double ) * 3 * nPoints; } break; default: case QGis::WKBMultiPolygon25D: { unsigned int nRings; memcpy( &nRings, wkb, sizeof( int ) ); wkb += sizeof( int ); for ( unsigned int j = 0; j < nRings; ++j ) { unsigned int nPoints; memcpy( &nPoints, wkb, sizeof( int ) ); wkb += sizeof( nPoints ) + sizeof( double ) * 3 * nPoints; } } break; } } } feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 ); } else { feature.setGeometryAndOwnership( 0, 0 ); } col++; } QgsFeatureId fid = 0; bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes(); switch ( mSource->mPrimaryKeyType ) { case pktOid: case pktTid: case pktInt: fid = mConn->getBinaryInt( queryResult, row, col++ ); if ( mSource->mPrimaryKeyType == pktInt && ( !subsetOfAttributes || fetchAttributes.contains( mSource->mPrimaryKeyAttrs[0] ) ) ) feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid ); break; case pktFidMap: { QList<QVariant> primaryKeyVals; Q_FOREACH ( int idx, mSource->mPrimaryKeyAttrs ) { const QgsField &fld = mSource->mFields[idx]; QVariant v = QgsPostgresProvider::convertValue( fld.type(), queryResult.PQgetvalue( row, col ) ); primaryKeyVals << v; if ( !subsetOfAttributes || fetchAttributes.contains( idx ) ) feature.setAttribute( idx, v ); col++; } fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) ); } break; case pktUnknown: Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" ); return false; } feature.setFeatureId( fid ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 ); // iterate attributes if ( subsetOfAttributes ) { Q_FOREACH ( int idx, fetchAttributes ) getFeatureAttribute( idx, queryResult, row, col, feature ); } else { for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
bool QgsPostgresFeatureIterator::nextFeature( QgsFeature& feature ) { feature.setValid( false ); if ( mClosed ) return false; #if 0 // featureAtId used to have some special checks - necessary? if ( !mUseQueue ) { QgsPostgresResult queryResult = P->mConnectionRO->PQexec( QString( "FETCH FORWARD 1 FROM %1" ).arg( mCursorName ) ); int rows = queryResult.PQntuples(); if ( rows == 0 ) { QgsMessageLog::logMessage( tr( "feature %1 not found" ).arg( featureId ), tr( "PostGIS" ) ); P->mConnectionRO->closeCursor( cursorName ); return false; } else if ( rows != 1 ) { QgsMessageLog::logMessage( tr( "found %1 features instead of just one." ).arg( rows ), tr( "PostGIS" ) ); } bool gotit = getFeature( queryResult, 0, feature ); feature.setValid( gotit ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups return gotit; } #endif if ( mFeatureQueue.empty() ) { QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName ); QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 ); if ( P->mConnectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); } QgsPostgresResult queryResult; for ( ;; ) { queryResult = P->mConnectionRO->PQgetResult(); if ( !queryResult.result() ) break; if ( queryResult.PQresultStatus() != PGRES_TUPLES_OK ) { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); break; } int rows = queryResult.PQntuples(); if ( rows == 0 ) continue; for ( int row = 0; row < rows; row++ ) { mFeatureQueue.enqueue( QgsFeature() ); getFeature( queryResult, row, mFeatureQueue.back() ); } // for each row in queue } } if ( mFeatureQueue.empty() ) { QgsDebugMsg( QString( "Finished after %1 features" ).arg( mFetched ) ); close(); if ( P->mFeaturesCounted < mFetched ) { QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( P->mFeaturesCounted ).arg( mFetched ) ); P->mFeaturesCounted = mFetched; } return false; } // Now return the next feature from the queue if ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) { feature.setGeometryAndOwnership( 0, 0 ); } else { QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership(); feature.setGeometry( featureGeom ); } feature.setFeatureId( mFeatureQueue.front().id() ); feature.setAttributes( mFeatureQueue.front().attributes() ); mFeatureQueue.dequeue(); mFetched++; feature.setValid( true ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups return true; }
bool QgsGPXProvider::nextFeature( QgsFeature& feature ) { feature.setValid( false ); bool result = false; QgsAttributeList::const_iterator iter; if ( mFeatureType == WaypointType ) { // go through the list of waypoints and return the first one that is in // the bounds rectangle for ( ; mWptIter != data->waypointsEnd(); ++mWptIter ) { const QgsWaypoint* wpt; wpt = &( *mWptIter ); if ( boundsCheck( wpt->lon, wpt->lat ) ) { feature.setFeatureId( wpt->id ); result = true; // some wkb voodoo if ( mFetchGeom ) { char* geo = new char[21]; std::memset( geo, 0, 21 ); geo[0] = QgsApplication::endian(); geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBPoint; std::memcpy( geo + 5, &wpt->lon, sizeof( double ) ); std::memcpy( geo + 13, &wpt->lat, sizeof( double ) ); feature.setGeometryAndOwnership(( unsigned char * )geo, sizeof( wkbPoint ) ); } feature.setValid( true ); // add attributes if they are wanted for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) { switch ( *iter ) { case NameAttr: feature.addAttribute( NameAttr, QVariant( wpt->name ) ); break; case EleAttr: if ( wpt->ele != -std::numeric_limits<double>::max() ) feature.addAttribute( EleAttr, QVariant( wpt->ele ) ); break; case SymAttr: feature.addAttribute( SymAttr, QVariant( wpt->sym ) ); break; case CmtAttr: feature.addAttribute( CmtAttr, QVariant( wpt->cmt ) ); break; case DscAttr: feature.addAttribute( DscAttr, QVariant( wpt->desc ) ); break; case SrcAttr: feature.addAttribute( SrcAttr, QVariant( wpt->src ) ); break; case URLAttr: feature.addAttribute( URLAttr, QVariant( wpt->url ) ); break; case URLNameAttr: feature.addAttribute( URLNameAttr, QVariant( wpt->urlname ) ); break; } } ++mWptIter; break; } } } else if ( mFeatureType == RouteType ) { // go through the routes and return the first one that is in the bounds // rectangle for ( ; mRteIter != data->routesEnd(); ++mRteIter ) { const QgsRoute* rte; rte = &( *mRteIter ); if ( rte->points.size() == 0 ) continue; const QgsRectangle& b( *mSelectionRectangle ); if (( rte->xMax >= b.xMinimum() ) && ( rte->xMin <= b.xMaximum() ) && ( rte->yMax >= b.yMinimum() ) && ( rte->yMin <= b.yMaximum() ) ) { // some wkb voodoo int nPoints = rte->points.size(); char* geo = new char[9 + 16 * nPoints]; std::memset( geo, 0, 9 + 16 * nPoints ); geo[0] = QgsApplication::endian(); geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString; std::memcpy( geo + 5, &nPoints, 4 ); for ( uint i = 0; i < rte->points.size(); ++i ) { std::memcpy( geo + 9 + 16 * i, &rte->points[i].lon, sizeof( double ) ); std::memcpy( geo + 9 + 16 * i + 8, &rte->points[i].lat, sizeof( double ) ); } //create QgsGeometry and use it for intersection test //if geometry is to be fetched, it is attached to the feature, otherwise we delete it QgsGeometry* theGeometry = new QgsGeometry(); theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * nPoints ); bool intersection = theGeometry->intersects( b );//use geos for precise intersection test if ( !intersection ) { delete theGeometry; } else { if ( mFetchGeom ) { feature.setGeometry( theGeometry ); } else { delete theGeometry; } feature.setFeatureId( rte->id ); result = true; feature.setValid( true ); // add attributes if they are wanted for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) { switch ( *iter ) { case NameAttr: feature.addAttribute( NameAttr, QVariant( rte->name ) ); break; case NumAttr: if ( rte->number != std::numeric_limits<int>::max() ) feature.addAttribute( NumAttr, QVariant( rte->number ) ); break; case CmtAttr: feature.addAttribute( CmtAttr, QVariant( rte->cmt ) ); break; case DscAttr: feature.addAttribute( DscAttr, QVariant( rte->desc ) ); break; case SrcAttr: feature.addAttribute( SrcAttr, QVariant( rte->src ) ); break; case URLAttr: feature.addAttribute( URLAttr, QVariant( rte->url ) ); break; case URLNameAttr: feature.addAttribute( URLNameAttr, QVariant( rte->urlname ) ); break; } } ++mRteIter; break; } //++mRteIter; //xbreak; } } } else if ( mFeatureType == TrackType ) { // go through the tracks and return the first one that is in the bounds // rectangle for ( ; mTrkIter != data->tracksEnd(); ++mTrkIter ) { const QgsTrack* trk; trk = &( *mTrkIter ); QgsDebugMsg( QString( "GPX feature track segments: %1" ).arg( trk->segments.size() ) ); if ( trk->segments.size() == 0 ) continue; // A track consists of several segments. Add all those segments into one. int totalPoints = 0;; for ( std::vector<QgsTrackSegment>::size_type i = 0; i < trk->segments.size(); i ++ ) { totalPoints += trk->segments[i].points.size(); } if ( totalPoints == 0 ) continue; QgsDebugMsg( "GPX feature track total points: " + QString::number( totalPoints ) ); const QgsRectangle& b( *mSelectionRectangle ); if (( trk->xMax >= b.xMinimum() ) && ( trk->xMin <= b.xMaximum() ) && ( trk->yMax >= b.yMinimum() ) && ( trk->yMin <= b.yMaximum() ) ) { // some wkb voodoo char* geo = new char[9 + 16 * totalPoints]; if ( !geo ) { QgsDebugMsg( "Too large track!!!" ); return false; } std::memset( geo, 0, 9 + 16 * totalPoints ); geo[0] = QgsApplication::endian(); geo[geo[0] == QgsApplication::NDR ? 1 : 4] = QGis::WKBLineString; std::memcpy( geo + 5, &totalPoints, 4 ); int thisPoint = 0; for ( std::vector<QgsTrackSegment>::size_type k = 0; k < trk->segments.size(); k++ ) { int nPoints = trk->segments[k].points.size(); for ( int i = 0; i < nPoints; ++i ) { std::memcpy( geo + 9 + 16 * thisPoint, &trk->segments[k].points[i].lon, sizeof( double ) ); std::memcpy( geo + 9 + 16 * thisPoint + 8, &trk->segments[k].points[i].lat, sizeof( double ) ); thisPoint++; } } //create QgsGeometry and use it for intersection test //if geometry is to be fetched, it is attached to the feature, otherwise we delete it QgsGeometry* theGeometry = new QgsGeometry(); theGeometry->fromWkb(( unsigned char * )geo, 9 + 16 * totalPoints ); bool intersection = theGeometry->intersects( b );//use geos for precise intersection test if ( !intersection ) //no intersection, delete geometry and move on { delete theGeometry; } else //intersection { if ( mFetchGeom ) { feature.setGeometry( theGeometry ); } else { delete theGeometry; } feature.setFeatureId( trk->id ); result = true; feature.setValid( true ); // add attributes if they are wanted for ( iter = mAttributesToFetch.begin(); iter != mAttributesToFetch.end(); ++iter ) { switch ( *iter ) { case NameAttr: feature.addAttribute( NameAttr, QVariant( trk->name ) ); break; case NumAttr: if ( trk->number != std::numeric_limits<int>::max() ) feature.addAttribute( NumAttr, QVariant( trk->number ) ); break; case CmtAttr: feature.addAttribute( CmtAttr, QVariant( trk->cmt ) ); break; case DscAttr: feature.addAttribute( DscAttr, QVariant( trk->desc ) ); break; case SrcAttr: feature.addAttribute( SrcAttr, QVariant( trk->src ) ); break; case URLAttr: feature.addAttribute( URLAttr, QVariant( trk->url ) ); break; case URLNameAttr: feature.addAttribute( URLNameAttr, QVariant( trk->urlname ) ); break; } } ++mTrkIter; break; } } } } if ( result ) { feature.setValid( true ); } return result; }
bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( mClosed ) return false; if ( mFeatureQueue.empty() ) { QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName ); QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 ); if ( P->mConnectionRO->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); } QgsPostgresResult queryResult; for ( ;; ) { queryResult = P->mConnectionRO->PQgetResult(); if ( !queryResult.result() ) break; if ( queryResult.PQresultStatus() != PGRES_TUPLES_OK ) { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( P->mConnectionRO->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); break; } int rows = queryResult.PQntuples(); if ( rows == 0 ) continue; for ( int row = 0; row < rows; row++ ) { mFeatureQueue.enqueue( QgsFeature() ); getFeature( queryResult, row, mFeatureQueue.back() ); } // for each row in queue } } if ( mFeatureQueue.empty() ) { QgsDebugMsg( QString( "Finished after %1 features" ).arg( mFetched ) ); close(); /* only updates the feature count if it was already once. * Otherwise, this would lead to false feature count if * an existing project is open at a restrictive extent. */ if ( P->mFeaturesCounted > 0 && P->mFeaturesCounted < mFetched ) { QgsDebugMsg( QString( "feature count adjusted from %1 to %2" ).arg( P->mFeaturesCounted ).arg( mFetched ) ); P->mFeaturesCounted = mFetched; } return false; } // Now return the next feature from the queue if ( mRequest.flags() & QgsFeatureRequest::NoGeometry ) { feature.setGeometryAndOwnership( 0, 0 ); } else { QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership(); feature.setGeometry( featureGeom ); } feature.setFeatureId( mFeatureQueue.front().id() ); feature.setAttributes( mFeatureQueue.front().attributes() ); mFeatureQueue.dequeue(); mFetched++; feature.setValid( true ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups return true; }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature ) { try { feature.initAttributes( P->fields().count() ); int col = 0; if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { int returnedLength = ::PQgetlength( queryResult.result(), row, col ); if ( returnedLength > 0 ) { unsigned char *featureGeom = new unsigned char[returnedLength + 1]; memset( featureGeom, 0, returnedLength + 1 ); memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength ); // modify 2.5D WKB types to make them compliant with OGR unsigned int wkbType; memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) ); // convert unsupported types to supported ones switch ( wkbType ) { case 15: // 2D polyhedral => multipolygon wkbType = 6; break; case 1015: // 3D polyhedral => multipolygon wkbType = 1006; break; case 17: // 2D triangle => polygon wkbType = 3; break; case 1017: // 3D triangle => polygon wkbType = 1003; break; case 16: // 2D TIN => multipolygon wkbType = 6; break; case 1016: // TIN => multipolygon wkbType = 1006; break; } // convert from postgis types to qgis types if ( wkbType >= 1000 ) { wkbType = wkbType - 1000 + QGis::WKBPoint25D - 1; } memcpy( featureGeom + 1, &wkbType, sizeof( wkbType ) ); // change wkb type of inner geometries if ( wkbType == QGis::WKBMultiPoint25D || wkbType == QGis::WKBMultiLineString25D || wkbType == QGis::WKBMultiPolygon25D ) { unsigned int numGeoms = *(( int* )( featureGeom + 5 ) ); unsigned char* wkb = featureGeom + 9; for ( unsigned int i = 0; i < numGeoms; ++i ) { unsigned int localType; memcpy( &localType, wkb + 1, sizeof( localType ) ); switch ( localType ) { case 15: // 2D polyhedral => multipolygon localType = 6; break; case 1015: // 3D polyhedral => multipolygon localType = 1006; break; case 17: // 2D triangle => polygon localType = 3; break; case 1017: // 3D triangle => polygon localType = 1003; break; case 16: // 2D TIN => multipolygon localType = 6; break; case 1016: // TIN => multipolygon localType = 1006; break; } if ( localType >= 1000 ) { localType = localType - 1000 + QGis::WKBPoint25D - 1; } memcpy( wkb + 1, &localType, sizeof( localType ) ); // skip endian and type info wkb += sizeof( unsigned int ) + 1; // skip coordinates switch ( wkbType ) { case QGis::WKBMultiPoint25D: wkb += sizeof( double ) * 3; break; case QGis::WKBMultiLineString25D: { unsigned int nPoints = *(( int* ) wkb ); wkb += sizeof( nPoints ); wkb += sizeof( double ) * 3 * nPoints; } break; default: case QGis::WKBMultiPolygon25D: { unsigned int nRings = *(( int* ) wkb ); wkb += sizeof( nRings ); for ( unsigned int j = 0; j < nRings; ++j ) { unsigned int nPoints = *(( int* ) wkb ); wkb += sizeof( nPoints ); wkb += sizeof( double ) * 3 * nPoints; } } break; } } } feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 ); } else { feature.setGeometryAndOwnership( 0, 0 ); } col++; } QgsFeatureId fid = 0; bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes(); switch ( P->mPrimaryKeyType ) { case QgsPostgresProvider::pktOid: case QgsPostgresProvider::pktTid: case QgsPostgresProvider::pktInt: fid = P->mConnectionRO->getBinaryInt( queryResult, row, col++ ); if ( P->mPrimaryKeyType == QgsPostgresProvider::pktInt && ( !subsetOfAttributes || fetchAttributes.contains( P->mPrimaryKeyAttrs[0] ) ) ) feature.setAttribute( P->mPrimaryKeyAttrs[0], fid ); break; case QgsPostgresProvider::pktFidMap: { QList<QVariant> primaryKeyVals; foreach ( int idx, P->mPrimaryKeyAttrs ) { const QgsField &fld = P->field( idx ); QVariant v = P->convertValue( fld.type(), queryResult.PQgetvalue( row, col ) ); primaryKeyVals << v; if ( !subsetOfAttributes || fetchAttributes.contains( idx ) ) feature.setAttribute( idx, v ); col++; } fid = P->lookupFid( QVariant( primaryKeyVals ) ); } break; case QgsPostgresProvider::pktUnknown: Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" ); return false; } feature.setFeatureId( fid ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 ); // iterate attributes if ( subsetOfAttributes ) { foreach ( int idx, fetchAttributes ) getFeatureAttribute( idx, queryResult, row, col, feature ); } else { for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) getFeatureAttribute( idx, queryResult, row, col, feature ); } return true; }
bool QgsOracleFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( !mQry.isActive() ) return false; for ( ;; ) { feature.initAttributes( mSource->mFields.count() ); feature.setGeometry( 0 ); if ( mRewind ) { mRewind = false; if ( !mQry.first() ) return true; } else if ( !mQry.next() ) { return false; } int col = 0; if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) == 0 || (( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && !mConnection->hasSpatial() ) ) { QByteArray *ba = static_cast<QByteArray*>( mQry.value( col++ ).data() ); unsigned char *copy = new unsigned char[ba->size()]; memcpy( copy, ba->constData(), ba->size() ); feature.setGeometryAndOwnership( copy, ba->size() ); if ( !mConnection->hasSpatial() && mRequest.filterType() == QgsFeatureRequest::FilterRect && ( mRequest.flags() & QgsFeatureRequest::ExactIntersect ) != 0 && ( !feature.geometry() || !feature.geometry()->intersects( mRequest.filterRect() ) ) ) { // skip feature that don't intersect with our rectangle QgsDebugMsg( "no intersect" ); continue; } if (( mRequest.flags() & QgsFeatureRequest::NoGeometry ) != 0 ) { feature.setGeometryAndOwnership( 0, 0 ); } } QgsFeatureId fid = 0; switch ( mSource->mPrimaryKeyType ) { case pktInt: // get 64bit integer from result fid = mQry.value( col++ ).toLongLong(); if ( mAttributeList.contains( mSource->mPrimaryKeyAttrs[0] ) ) feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid ); break; case pktRowId: case pktFidMap: { QList<QVariant> primaryKeyVals; if ( mSource->mPrimaryKeyType == pktFidMap ) { foreach ( int idx, mSource->mPrimaryKeyAttrs ) { const QgsField &fld = mSource->mFields[idx]; QVariant v = mQry.value( col ); if ( v.type() != fld.type() ) v = QgsVectorDataProvider::convertValue( fld.type(), v.toString() ); primaryKeyVals << v; if ( mAttributeList.contains( idx ) ) feature.setAttribute( idx, v ); col++; } } else { primaryKeyVals << mQry.value( col++ ); } fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) ); } break; case pktUnknown: Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" ); return false; }
bool QgsDelimitedTextProvider::nextFeature( QgsFeature& feature ) { // before we do anything else, assume that there's something wrong with // the feature feature.setValid( false ); while ( ! mStream->atEnd() ) { double x = 0.0; double y = 0.0; QString line = mStream->readLine(); // Default local 8 bit encoding // lex the tokens from the current data line QStringList tokens; if ( mDelimiterType == "regexp" ) tokens = line.split( mDelimiterRegexp ); else tokens = line.split( mDelimiter ); bool xOk = false; bool yOk = false; // Skip indexing malformed lines. if ( attributeFields.size() == tokens.size() ) { x = tokens[mXFieldIndex].toDouble( &xOk ); y = tokens[mYFieldIndex].toDouble( &yOk ); } if ( !( xOk && yOk ) ) { // Accumulate any lines that weren't ok, to report on them // later, and look at the next line in the file, but only if // we need to. QgsDebugMsg( "Malformed line : " + line ); if ( mShowInvalidLines ) mInvalidLines << line; continue; } // Give every valid line in the file an id, even if it's not // in the current extent or bounds. ++mFid; // increment to next feature ID // skip the feature if it's out of current bounds if ( ! boundsCheck( x, y ) ) continue; // at this point, one way or another, the current feature values // are valid feature.setValid( true ); feature.setFeatureId( mFid ); QByteArray buffer; QDataStream s( &buffer, static_cast<QIODevice::OpenMode>( QIODevice::WriteOnly ) ); // open on buffers's data switch ( QgsApplication::endian() ) { case QgsApplication::NDR : // we're on a little-endian platform, so tell the data // stream to use that s.setByteOrder( QDataStream::LittleEndian ); s << ( quint8 )1; // 1 is for little-endian break; case QgsApplication::XDR : // don't change byte order since QDataStream is big endian by default s << ( quint8 )0; // 0 is for big-endian break; default : qDebug( "%s:%d unknown endian", __FILE__, __LINE__ ); //delete [] geometry; return false; } s << ( quint32 )QGis::WKBPoint; s << x; s << y; unsigned char* geometry = new unsigned char[buffer.size()]; memcpy( geometry, buffer.data(), buffer.size() ); feature.setGeometryAndOwnership( geometry, sizeof( wkbPoint ) ); for ( QgsAttributeList::const_iterator i = mAttributesToFetch.begin(); i != mAttributesToFetch.end(); ++i ) { QVariant val; switch ( attributeFields[*i].type() ) { case QVariant::Int: val = QVariant( tokens[*i].toInt() ); break; case QVariant::Double: val = QVariant( tokens[*i].toDouble() ); break; default: val = QVariant( tokens[*i] ); break; } feature.addAttribute( *i, val ); } // We have a good line, so return return true; } // ! textStream EOF // End of the file. If there are any lines that couldn't be // loaded, display them now. if ( mShowInvalidLines && !mInvalidLines.isEmpty() ) { mShowInvalidLines = false; QgsMessageOutput* output = QgsMessageOutput::createMessageOutput(); output->setTitle( tr( "Error" ) ); output->setMessage( tr( "Note: the following lines were not loaded because Qgis was " "unable to determine values for the x and y coordinates:\n" ), QgsMessageOutput::MessageText ); output->appendMessage( "Start of invalid lines." ); for ( int i = 0; i < mInvalidLines.size(); ++i ) output->appendMessage( mInvalidLines.at( i ) ); output->appendMessage( "End of invalid lines." ); output->showMessage(); // We no longer need these lines. mInvalidLines.empty(); } return false; } // nextFeature
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature ) { try { feature.initAttributes( P->fields().count() ); int col = 0; if ( !( mRequest.flags() & QgsFeatureRequest::NoGeometry ) ) { int returnedLength = ::PQgetlength( queryResult.result(), row, col ); if ( returnedLength > 0 ) { unsigned char *featureGeom = new unsigned char[returnedLength + 1]; memset( featureGeom, 0, returnedLength + 1 ); memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength ); feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 ); } else { feature.setGeometryAndOwnership( 0, 0 ); } col++; } QgsFeatureId fid = 0; bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes(); switch ( P->mPrimaryKeyType ) { case QgsPostgresProvider::pktOid: case QgsPostgresProvider::pktTid: case QgsPostgresProvider::pktInt: fid = P->mConnectionRO->getBinaryInt( queryResult, row, col++ ); if ( P->mPrimaryKeyType == QgsPostgresProvider::pktInt && ( !subsetOfAttributes || fetchAttributes.contains( P->mPrimaryKeyAttrs[0] ) ) ) feature.setAttribute( P->mPrimaryKeyAttrs[0], fid ); break; case QgsPostgresProvider::pktFidMap: { QList<QVariant> primaryKeyVals; foreach ( int idx, P->mPrimaryKeyAttrs ) { const QgsField &fld = P->field( idx ); QVariant v = P->convertValue( fld.type(), queryResult.PQgetvalue( row, col ) ); primaryKeyVals << v; if ( !subsetOfAttributes || fetchAttributes.contains( idx ) ) feature.setAttribute( idx, v ); col++; } fid = P->lookupFid( QVariant( primaryKeyVals ) ); } break; case QgsPostgresProvider::pktUnknown: Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" ); return false; } feature.setFeatureId( fid ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 ); // iterate attributes if ( subsetOfAttributes ) { foreach ( int idx, fetchAttributes ) getFeatureAttribute( idx, queryResult, row, col, feature ); } else { for ( int idx = 0; idx < P->mAttributeFields.count(); ++idx ) getFeatureAttribute( idx, queryResult, row, col, feature ); } return true; }
bool QgsPostgresFeatureIterator::getFeature( QgsPostgresResult &queryResult, int row, QgsFeature &feature ) { feature.initAttributes( mSource->mFields.count() ); int col = 0; if ( mFetchGeometry ) { int returnedLength = ::PQgetlength( queryResult.result(), row, col ); if ( returnedLength > 0 ) { unsigned char *featureGeom = new unsigned char[returnedLength + 1]; memcpy( featureGeom, PQgetvalue( queryResult.result(), row, col ), returnedLength ); memset( featureGeom + returnedLength, 0, 1 ); unsigned int wkbType; memcpy( &wkbType, featureGeom + 1, sizeof( wkbType ) ); QgsWKBTypes::Type newType = QgsPostgresConn::wkbTypeFromOgcWkbType( wkbType ); if (( unsigned int )newType != wkbType ) { // overwrite type unsigned int n = newType; memcpy( featureGeom + 1, &n, sizeof( n ) ); } // PostGIS stores TIN as a collection of Triangles. // Since Triangles are not supported, they have to be converted to Polygons const int nDims = 2 + ( QgsWKBTypes::hasZ( newType ) ? 1 : 0 ) + ( QgsWKBTypes::hasM( newType ) ? 1 : 0 ); if ( wkbType % 1000 == 16 ) { unsigned int numGeoms; memcpy( &numGeoms, featureGeom + 5, sizeof( unsigned int ) ); unsigned char *wkb = featureGeom + 9; for ( unsigned int i = 0; i < numGeoms; ++i ) { const unsigned int localType = QgsWKBTypes::singleType( newType ); // polygon(Z|M) memcpy( wkb + 1, &localType, sizeof( localType ) ); // skip endian and type info wkb += sizeof( unsigned int ) + 1; // skip coordinates unsigned int nRings; memcpy( &nRings, wkb, sizeof( int ) ); wkb += sizeof( int ); for ( unsigned int j = 0; j < nRings; ++j ) { unsigned int nPoints; memcpy( &nPoints, wkb, sizeof( int ) ); wkb += sizeof( nPoints ) + sizeof( double ) * nDims * nPoints; } } } feature.setGeometryAndOwnership( featureGeom, returnedLength + 1 ); } else { feature.setGeometryAndOwnership( 0, 0 ); } col++; } QgsFeatureId fid = 0; bool subsetOfAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; const QgsAttributeList& fetchAttributes = mRequest.subsetOfAttributes(); switch ( mSource->mPrimaryKeyType ) { case pktOid: case pktTid: case pktInt: fid = mConn->getBinaryInt( queryResult, row, col++ ); if ( mSource->mPrimaryKeyType == pktInt && ( !subsetOfAttributes || fetchAttributes.contains( mSource->mPrimaryKeyAttrs[0] ) ) ) feature.setAttribute( mSource->mPrimaryKeyAttrs[0], fid ); break; case pktFidMap: { QList<QVariant> primaryKeyVals; Q_FOREACH ( int idx, mSource->mPrimaryKeyAttrs ) { const QgsField &fld = mSource->mFields.at( idx ); QVariant v = QgsPostgresProvider::convertValue( fld.type(), queryResult.PQgetvalue( row, col ) ); primaryKeyVals << v; if ( !subsetOfAttributes || fetchAttributes.contains( idx ) ) feature.setAttribute( idx, v ); col++; } fid = mSource->mShared->lookupFid( QVariant( primaryKeyVals ) ); } break; case pktUnknown: Q_ASSERT( !"FAILURE: cannot get feature with unknown primary key" ); return false; } feature.setFeatureId( fid ); QgsDebugMsgLevel( QString( "fid=%1" ).arg( fid ), 4 ); // iterate attributes if ( subsetOfAttributes ) { Q_FOREACH ( int idx, fetchAttributes ) getFeatureAttribute( idx, queryResult, row, col, feature ); } else { for ( int idx = 0; idx < mSource->mFields.count(); ++idx )
bool QgsSqlAnywhereFeatureIterator::nextFeature( QgsFeature& feature, SqlAnyStatement *stmt ) { feature.setValid( false ); bool fetchGeometry = !( mRequest.flags() & QgsFeatureRequest::NoGeometry ); bool subsetAttributes = mRequest.flags() & QgsFeatureRequest::SubsetOfAttributes; if ( mClosed ) return false; if ( !P->mConnRO || !P->mConnRO->isAlive() ) { SaDebugMsg( "No database connection." ); return false; } bool ok; int id; a_sqlany_data_value geom; unsigned char *geomBuf = NULL; ok = ( stmt != NULL && stmt->fetchNext() ); // if no more rows... if ( !ok ) return false; if ( !fetchGeometry ) feature.setGeometryAndOwnership( 0, 0 ); int numAttributes = P->fields().count(); // also used later for sanity check feature.initAttributes( numAttributes ); feature.setFields( &P->mAttributeFields ); // allow name-based attribute lookups int i = 0; int numcols = stmt->numCols(); int colidx = 0; // Refers to which column we're on in "feature" (the row) for ( i = 0; i < numcols; i++ ) { if ( i == 0 ) { // first column always contains primary key ok = stmt->getInt( i, id ); if ( !ok ) break; QgsDebugMsgLevel( QString( "pid=%1" ).arg( id ), 3 ); feature.setFeatureId( id ); } else if ( i == 1 && fetchGeometry ) { // second column contains QKB geometry value ok = stmt->getColumn( i, &geom ); if ( !ok ) break; QgsDebugMsgLevel( QString( "retrieved geometry column" ), 3 ); geomBuf = new unsigned char[ *geom.length + 1 ]; memset( geomBuf, '\0', *geom.length ); memcpy( geomBuf, geom.buffer, *geom.length ); feature.setGeometryAndOwnership( geomBuf, *geom.length + 1 ); } else { if ( i == 1 ) { feature.setGeometryAndOwnership( 0, 0 ); // no geometry to fetch } int attrIndex = subsetAttributes ? mRequest.subsetOfAttributes()[colidx++] : colidx++; QVariant val; ok = stmt->getQVariant( i, val ); // ok may be false if value was NULL, but this is a valid return // Sanity check before setting the attribute value if ( colidx - 1 == i // First column is always pk, so colidx should be at least 1 behind || ( colidx - 1 == i - 1 && fetchGeometry ) // if fetchGeometry is true, colidx should be 2 behind || attrIndex >= numAttributes ) // index should always be less than the count { SaDebugMsg( QString( "Error retrieving feature column %1 with attribute index %2" ).arg( i ).arg( attrIndex ) ); return false; } // So now this should not crash. feature.setAttribute( attrIndex, val ); } } feature.setValid( true ); return true; }
bool QgsPostgresFeatureIterator::fetchFeature( QgsFeature& feature ) { feature.setValid( false ); if ( mClosed ) return false; if ( mFeatureQueue.empty() ) { QString fetch = QString( "FETCH FORWARD %1 FROM %2" ).arg( mFeatureQueueSize ).arg( mCursorName ); QgsDebugMsgLevel( QString( "fetching %1 features." ).arg( mFeatureQueueSize ), 4 ); if ( mConn->PQsendQuery( fetch ) == 0 ) // fetch features asynchronously { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); } QgsPostgresResult queryResult; for ( ;; ) { queryResult = mConn->PQgetResult(); if ( !queryResult.result() ) break; if ( queryResult.PQresultStatus() != PGRES_TUPLES_OK ) { QgsMessageLog::logMessage( QObject::tr( "Fetching from cursor %1 failed\nDatabase error: %2" ).arg( mCursorName ).arg( mConn->PQerrorMessage() ), QObject::tr( "PostGIS" ) ); break; } int rows = queryResult.PQntuples(); if ( rows == 0 ) continue; for ( int row = 0; row < rows; row++ ) { mFeatureQueue.enqueue( QgsFeature() ); getFeature( queryResult, row, mFeatureQueue.back() ); } // for each row in queue } } if ( mFeatureQueue.empty() ) { QgsDebugMsg( QString( "Finished after %1 features" ).arg( mFetched ) ); close(); mSource->mShared->ensureFeaturesCountedAtLeast( mFetched ); return false; } // Now return the next feature from the queue if ( !mFetchGeometry ) { feature.setGeometryAndOwnership( 0, 0 ); } else { QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership(); feature.setGeometry( featureGeom ); } feature.setFeatureId( mFeatureQueue.front().id() ); feature.setAttributes( mFeatureQueue.front().attributes() ); mFeatureQueue.dequeue(); mFetched++; feature.setValid( true ); feature.setFields( &mSource->mFields ); // allow name-based attribute lookups return true; }