📄 qgspostgresprovider.cpp
字号:
return PQexecNR(connection, declare.toUtf8()); } catch(PGFieldNotFound) { return false; }}bool QgsPostgresProvider::getFeature(PGresult *queryResult, int row, bool fetchGeometry, QgsFeature &feature, const QgsAttributeList &fetchAttributes){ try { int oid = *(int *)PQgetvalue(queryResult, row, 0); if (swapEndian) oid = ntohl(oid); // convert oid to opposite endian feature.setFeatureId(oid); int col; // first attribute column after geometry if (fetchGeometry) { int returnedLength = PQgetlength(queryResult, row, 1); if(returnedLength > 0) { unsigned char *featureGeom = new unsigned char[returnedLength + 1]; memset(featureGeom, '\0', returnedLength + 1); memcpy(featureGeom, PQgetvalue(queryResult, row, 1), returnedLength); feature.setGeometryAndOwnership(featureGeom, returnedLength + 1); } else { feature.setGeometryAndOwnership(0, 0); QgsDebugMsg("Couldn't get the feature geometry in binary form"); } col = 2; } else { col = 1; } // iterate attributes for(QgsAttributeList::const_iterator it=fetchAttributes.constBegin(); it!=fetchAttributes.constEnd(); it++) { const QgsField &fld = field(*it); if( fld.name() == primaryKey ) { // primary key was already processed feature.addAttribute(*it, QString::number(oid) ); continue; } if( !PQgetisnull(queryResult, row, col) ) { QString val = QString::fromUtf8(PQgetvalue(queryResult, row, col)); switch (fld.type()) { case QVariant::LongLong: feature.addAttribute(*it, val.toLongLong()); break; case QVariant::Int: feature.addAttribute(*it, val.toInt()); break; case QVariant::Double: feature.addAttribute(*it, val.toDouble()); break; case QVariant::String: feature.addAttribute(*it, val); break; default: QgsDebugMsg( QString("feature %1, field %2, value '%3': unexpected variant type %4 considered as NULL") .arg( oid ) .arg( fld.name() ) .arg( val ) .arg( fld.type() ) ); feature.addAttribute(*it, QVariant(QString::null)); } } else { feature.addAttribute(*it, QVariant(QString::null)); } col++; } return true; } catch(PGFieldNotFound) { return false; }}void QgsPostgresProvider::select(QgsAttributeList fetchAttributes, QgsRect rect, bool fetchGeometry, bool useIntersect){ QString cursorName = QString("qgisf%1").arg(providerId); if(mFetching) { PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8() ); mFetching=false; while(!mFeatureQueue.empty()) { mFeatureQueue.pop(); } } QString whereClause; if(!rect.isEmpty()) { if(useIntersect) { // Contributed by #qgis irc "creeping" // This version actually invokes PostGIS's use of spatial indexes whereClause = QString("%1 && setsrid('BOX3D(%2)'::box3d,%3) and intersects(%1,setsrid('BOX3D(%2)'::box3d,%3))") .arg( quotedIdentifier(geometryColumn) ) .arg( rect.asWKTCoords() ) .arg( srid ); } else { whereClause = QString("%1 && setsrid('BOX3D(%2)'::box3d,%3)") .arg( quotedIdentifier(geometryColumn) ) .arg( rect.asWKTCoords() ) .arg( srid ); } } if( !sqlWhereClause.isEmpty() ) { if (!whereClause.isEmpty()) whereClause += " and "; whereClause += "(" + sqlWhereClause + ")"; } mFetchGeom = fetchGeometry; mAttributesToFetch = fetchAttributes; if( !declareCursor( cursorName, fetchAttributes, fetchGeometry, whereClause ) ) return; mFetching = true;}bool QgsPostgresProvider::getNextFeature(QgsFeature& feature){ QString cursorName = QString("qgisf%1").arg(providerId); if (!valid) { QgsDebugMsg("Read attempt on an invalid postgresql data source"); return false; } if( mFeatureQueue.empty() ) { QString fetch = QString("fetch forward %1 from %2").arg(mFeatureQueueSize).arg(cursorName); if(PQsendQuery(connection, fetch.toUtf8()) == 0) //fetch features in asynchronously { qWarning("PQsendQuery failed (1)"); } PGresult *queryResult; while( (queryResult = PQgetResult(connection)) ) { int rows = PQntuples(queryResult); if (rows == 0) continue; for (int row = 0; row < rows; row++) { mFeatureQueue.push(QgsFeature()); getFeature(queryResult, row, mFetchGeom, mFeatureQueue.back(), mAttributesToFetch); } // for each row in queue PQclear(queryResult); } } if( mFeatureQueue.empty() ) { QgsDebugMsg("End of features"); return false; } // Now return the next feature from the queue if(mFetchGeom) { QgsGeometry* featureGeom = mFeatureQueue.front().geometryAndOwnership(); feature.setGeometry(featureGeom); } else { feature.setGeometryAndOwnership(0, 0); } feature.setFeatureId(mFeatureQueue.front().featureId()); feature.setAttributeMap(mFeatureQueue.front().attributeMap()); mFeatureQueue.pop(); return true;}bool QgsPostgresProvider::getFeatureAtId(int featureId, QgsFeature& feature, bool fetchGeometry, QgsAttributeList fetchAttributes){ QString cursorName = QString("qgisfid%1").arg(providerId); if( !declareCursor( cursorName, fetchAttributes, fetchGeometry, QString("%2=%3").arg(quotedIdentifier(primaryKey)).arg(featureId) ) ) return false; PGresult *queryResult = PQexec(connection, QString("fetch forward 1 from %1").arg(cursorName).toUtf8()); if(queryResult==0) return false; int rows = PQntuples(queryResult); if (rows == 0) { QgsDebugMsg("feature " + QString::number(featureId) + " not found"); PQclear(queryResult); PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8()); return false; } else if(rows != 1) { QgsDebugMsg( QString("found %1 features instead of just one.").arg(rows) ); } bool gotit = getFeature(queryResult, 0, fetchGeometry, feature, fetchAttributes); PQclear(queryResult); PQexecNR(connection, QString("CLOSE %1").arg(cursorName).toUtf8()); return gotit;}QgsDataSourceURI& QgsPostgresProvider::getURI(){ return mUri;}void QgsPostgresProvider::setExtent( QgsRect& newExtent ){ layerExtent.setXmax( newExtent.xMax() ); layerExtent.setXmin( newExtent.xMin() ); layerExtent.setYmax( newExtent.yMax() ); layerExtent.setYmin( newExtent.yMin() );}// TODO - make this function return the real extent_QgsRect QgsPostgresProvider::extent(){ return layerExtent; //extent_->MinX, extent_->MinY, extent_->MaxX, extent_->MaxY);}/** * Return the feature type */QGis::WKBTYPE QgsPostgresProvider::geometryType() const{ return geomType;}/** * Return the feature type */long QgsPostgresProvider::featureCount() const{ return numberFeatures;}const QgsField &QgsPostgresProvider::field(int index) const{ QgsFieldMap::const_iterator it = attributeFields.find(index); if( it==attributeFields.constEnd() ) { QgsDebugMsg("Field " + QString::number(index) + " not found."); throw PGFieldNotFound(); } return it.value();}/** * Return the number of fields */uint QgsPostgresProvider::fieldCount() const{ return attributeFields.size();}const QgsFieldMap & QgsPostgresProvider::fields() const{ return attributeFields;}QString QgsPostgresProvider::dataComment() const{ return mDataComment;}void QgsPostgresProvider::reset(){ if(mFetching) { //move cursor to first record PQexecNR(connection, QString("move 0 in qgisf%1").arg(providerId).toUtf8()); } mFeatureQueue.empty(); loadFields();}/** @todo XXX Perhaps this should be promoted to QgsDataProvider? */QString QgsPostgresProvider::endianString(){ switch ( QgsApplication::endian() ) { case QgsApplication::NDR : return QString("NDR"); break; case QgsApplication::XDR : return QString("XDR"); break; default : return QString("UNKNOWN"); }}void QgsPostgresProvider::loadFields(){ QgsDebugMsg("Loading fields for table " + mTableName); // Get the relation oid for use in later queries QString sql = QString("SELECT regclass(%1)::oid").arg( quotedValue(mSchemaTableName) ); PGresult *tresult= PQexec(connection, sql.toUtf8()); QString tableoid = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); PQclear(tresult); // Get the table description sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=0").arg( tableoid ); tresult = PQexec(connection, sql.toUtf8()); if (PQntuples(tresult) > 0) mDataComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); PQclear(tresult); // Populate the field vector for this layer. The field vector contains // field name, type, length, and precision (if numeric) sql = QString("select * from %1 limit 0").arg ( mSchemaTableName ); PGresult *result = PQexec(connection, sql.toUtf8()); //--std::cout << "Field: Name, Type, Size, Modifier:" << std::endl; // The queries inside this loop could possibly be combined into one // single query - this would make the code run faster. attributeFields.clear(); for (int i = 0; i < PQnfields(result); i++) { QString fieldName = QString::fromUtf8(PQfname(result, i)); int fldtyp = PQftype(result, i); QString typOid = QString().setNum(fldtyp); int fieldModifier = PQfmod(result, i); QString fieldComment(""); sql = QString("SELECT typname,typlen FROM pg_type WHERE oid=%1").arg(typOid); // just oid; needs more work to support array type // "oid = (SELECT Distinct typelem FROM pg_type WHERE " //needs DISTINCT to guard against 2 or more rows on int2 // "typelem = " + typOid + " AND typlen = -1)"; PGresult* oidResult = PQexec(connection, sql.toUtf8()); QString fieldTypeName = QString::fromUtf8(PQgetvalue(oidResult, 0, 0)); QString fieldSize = QString::fromUtf8(PQgetvalue(oidResult, 0, 1)); PQclear(oidResult); sql = QString("SELECT attnum FROM pg_attribute WHERE attrelid=%1 AND attname=%2") .arg( tableoid ).arg( quotedValue(fieldName) ); PGresult *tresult = PQexec(connection, sql.toUtf8()); QString attnum = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); PQclear(tresult); sql = QString("SELECT description FROM pg_description WHERE objoid=%1 AND objsubid=%2") .arg( tableoid ).arg( attnum ); tresult = PQexec(connection, sql.toUtf8()); if (PQntuples(tresult) > 0) fieldComment = QString::fromUtf8(PQgetvalue(tresult, 0, 0)); PQclear(tresult); if(fieldName!=geometryColumn) { QVariant::Type fieldType; bool isArray = fieldTypeName.startsWith("_"); if(isArray) fieldTypeName = fieldTypeName.mid(1); if (fieldTypeName == "int8" ) fieldType = QVariant::LongLong; else if (fieldTypeName.startsWith("int") || fieldTypeName=="serial" ) fieldType = QVariant::Int; else if (fieldTypeName == "real" || fieldTypeName == "double precision" || fieldTypeName.startsWith("float") || fieldTypeName == "numeric" ) fieldType = QVariant::Double; else if (fieldTypeName == "text" ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -