📄 tabrelation.cpp
字号:
// tabrelation.cpp: implementation of the TABRelation class.////////////////////////////////////////////////////////////////////////#include "tabrelation.h"#include "ugk_errhandle.h"#include "ugk_memopr.h"#include "ugk_string.h"/********************************************************************** * TABRelation::TABRelation() * * Constructor. **********************************************************************/TABRelation::TABRelation(){ m_poMainTable = NULL; m_pszMainFieldName = NULL; m_nMainFieldNo = -1; m_poRelTable = NULL; m_pszRelFieldName = NULL; m_nRelFieldNo = -1; m_nRelFieldIndexNo = -1; m_poRelINDFileRef = NULL; m_nUniqueRecordNo = 0; m_panMainTableFieldMap = NULL; m_panRelTableFieldMap = NULL; m_poDefn = NULL;}/********************************************************************** * TABRelation::~TABRelation() * * Destructor. **********************************************************************/TABRelation::~TABRelation(){ ResetAllMembers();}/********************************************************************** * TABRelation::ResetAllMembers() * * Reset all class members. **********************************************************************/void TABRelation::ResetAllMembers(){ m_poMainTable = NULL; UGK_Free(m_pszMainFieldName); m_pszMainFieldName = NULL; m_nMainFieldNo = -1; m_poRelTable = NULL; UGK_Free(m_pszRelFieldName); m_pszRelFieldName = NULL; m_nRelFieldNo = -1; m_nRelFieldIndexNo = -1; m_nUniqueRecordNo = 0; // No need to close m_poRelINDFileRef since we only got a ref. to it m_poRelINDFileRef = NULL; UGK_Free(m_panMainTableFieldMap); m_panMainTableFieldMap = NULL; UGK_Free(m_panRelTableFieldMap); m_panRelTableFieldMap = NULL; /*----------------------------------------------------------------- * Note: we have to check the reference count before deleting m_poDefn *----------------------------------------------------------------*/ if (m_poDefn && m_poDefn->Dereference() == 0) delete m_poDefn; m_poDefn = NULL;}/********************************************************************** * TABRelation::Init() * * Set the details of the relation: the main and related tables, the fields * through which they will be connected, and the list of fields to select. * After this call, we are ready to read data records. * * For write access, Init() is called with pszMain/RelFieldName and * **papszSelectedFields passed as NULL. They will have to be set through * other methods before a first feature can be written. * * A new UGKFeatureDefn is also built for the combined tables. * * Returns 0 on success, or -1 or error. **********************************************************************/int TABRelation::Init(const char *pszViewName, TABFile *poMainTable, TABFile *poRelTable, const char *pszMainFieldName, const char *pszRelFieldName, char **papszSelectedFields){ if (poMainTable == NULL || poRelTable == NULL) return -1; // We'll need the feature Defn later... UGKFeatureDefn *poMainDefn, *poRelDefn; poMainDefn = poMainTable->GetLayerDefn(); poRelDefn = poRelTable->GetLayerDefn(); /*----------------------------------------------------------------- * Keep info for later use about source tables, etc. *----------------------------------------------------------------*/ ResetAllMembers(); m_poMainTable = poMainTable; if (pszMainFieldName) { m_pszMainFieldName = UGKStrdup(pszMainFieldName); m_nMainFieldNo = poMainDefn->GetFieldIndex(pszMainFieldName); } m_poRelTable = poRelTable; if (pszRelFieldName) { m_pszRelFieldName = UGKStrdup(pszRelFieldName); m_nRelFieldNo = poRelDefn->GetFieldIndex(pszRelFieldName); m_nRelFieldIndexNo = poRelTable->GetFieldIndexNumber(m_nRelFieldNo); m_poRelINDFileRef = poRelTable->GetINDFileRef(); if (m_nRelFieldIndexNo >= 0 && m_poRelINDFileRef == NULL) { UGKError(ET_Failure, UGKErr_FileIO, "Field %s is indexed but the .IND file is missing.", pszRelFieldName); return -1; } } /*----------------------------------------------------------------- * Init field maps. For each field in each table, a -1 means that * the field is not selected, and a value >=0 is the index of the * field in the view's FeatureDefn *----------------------------------------------------------------*/ int i; int numFields1 = (poMainDefn?poMainDefn->GetFieldCount():0); int numFields2 = (poRelDefn?poRelDefn->GetFieldCount():0); m_panMainTableFieldMap = (int*)UGK_Malloc((numFields1+1)*sizeof(int)); for(i=0; i<numFields1; i++) m_panMainTableFieldMap[i] = -1; m_panRelTableFieldMap = (int*)UGK_Malloc((numFields2+1)*sizeof(int)); for(i=0; i<numFields2; i++) m_panRelTableFieldMap[i] = -1; /*----------------------------------------------------------------- * If selectedFields = "*" then select all fields from both tables *----------------------------------------------------------------*/ if (CountOfList(papszSelectedFields) == 1 && EQUAL(papszSelectedFields[0], "*") ) { FreeStrList(papszSelectedFields); papszSelectedFields = NULL; for(i=0; i<numFields1; i++) { UGKFieldDefn *poFieldDefn = poMainDefn->GetFieldDefn(i); papszSelectedFields = AddStringToList(papszSelectedFields, poFieldDefn->GetNameRef()); } for(i=0; i<numFields2; i++) { UGKFieldDefn *poFieldDefn = poRelDefn->GetFieldDefn(i); if (FindStrInList(papszSelectedFields, poFieldDefn->GetNameRef()) != -1) continue; // Avoid duplicate field name in view papszSelectedFields = AddStringToList(papszSelectedFields, poFieldDefn->GetNameRef()); } } /*----------------------------------------------------------------- * Create new FeatureDefn and copy selected fields definitions * while updating the appropriate field maps. *----------------------------------------------------------------*/ int nIndex, numSelFields = CountOfList(papszSelectedFields); UGKFieldDefn *poFieldDefn; m_poDefn = new UGKFeatureDefn(pszViewName); // Ref count defaults to 0... set it to 1 m_poDefn->Reference(); for(i=0; i<numSelFields ; i++) { if (poMainDefn && (nIndex=poMainDefn->GetFieldIndex(papszSelectedFields[i])) >=0) { /* Field from the main table */ poFieldDefn = poMainDefn->GetFieldDefn(nIndex); m_poDefn->AddFieldDefn(poFieldDefn); m_panMainTableFieldMap[nIndex] = m_poDefn->GetFieldCount()-1; } else if (poRelDefn && (nIndex=poRelDefn->GetFieldIndex(papszSelectedFields[i]))>=0) { /* Field from the related table */ poFieldDefn = poRelDefn->GetFieldDefn(nIndex); m_poDefn->AddFieldDefn(poFieldDefn); m_panRelTableFieldMap[nIndex] = m_poDefn->GetFieldCount()-1; } else { // Hummm... field does not exist... likely an unsupported feature! // At least send a warning and ignore the field. UGKError(ET_Warning, UGKErr_IllegalArg, "Selected Field %s not found in source tables %s and %s", papszSelectedFields[i], poMainDefn->GetName(), poRelDefn->GetName()); } } return 0;}/********************************************************************** * TABRelation::CreateRelFields() * * For write access, create the integer fields in each table that will * link them, and setup everything to be ready to write the first feature. * * This function should be called just before writing the first feature. * * Returns 0 on success, or -1 or error. **********************************************************************/int TABRelation::CreateRelFields(){ int i; /*----------------------------------------------------------------- * Create the field in each table. * The default name is "MI_refnum" but if a field with the same name * already exists then we'll try to generate a unique name. *----------------------------------------------------------------*/ m_pszMainFieldName = UGKStrdup("MI_Refnum "); strcpy(m_pszMainFieldName, "MI_Refnum"); i = 1; while(m_poDefn->GetFieldIndex(m_pszMainFieldName) >= 0) { sprintf(m_pszMainFieldName, "MI_Refnum_%d", i++); } m_pszRelFieldName = UGKStrdup(m_pszMainFieldName); m_nMainFieldNo = m_nRelFieldNo = -1; if (m_poMainTable->AddFieldNative(m_pszMainFieldName, TABFInteger, 0, 0) == 0) m_nMainFieldNo = m_poMainTable->GetLayerDefn()->GetFieldCount()-1; if (m_poRelTable->AddFieldNative(m_pszRelFieldName, TABFInteger, 0, 0) == 0) m_nRelFieldNo = m_poRelTable->GetLayerDefn()->GetFieldCount()-1; if (m_nMainFieldNo == -1 || m_nRelFieldNo == -1) return -1; if (m_poMainTable->SetFieldIndexed(m_nMainFieldNo) == -1) return -1; if ((m_nRelFieldIndexNo=m_poRelTable->SetFieldIndexed(m_nRelFieldNo)) ==-1) return -1; m_poRelINDFileRef = m_poRelTable->GetINDFileRef(); /*----------------------------------------------------------------- * Update field maps *----------------------------------------------------------------*/ UGKFeatureDefn *poMainDefn, *poRelDefn; poMainDefn = m_poMainTable->GetLayerDefn(); poRelDefn = m_poRelTable->GetLayerDefn(); m_panMainTableFieldMap = (int*)UGK_Realloc(m_panMainTableFieldMap, poMainDefn->GetFieldCount()*sizeof(int)); m_panMainTableFieldMap[poMainDefn->GetFieldCount()-1] = -1; m_panRelTableFieldMap = (int*)UGK_Realloc(m_panRelTableFieldMap, poRelDefn->GetFieldCount()*sizeof(int)); m_panRelTableFieldMap[poRelDefn->GetFieldCount()-1] = -1; /*----------------------------------------------------------------- * Make sure the first unique field (in poRelTable) is indexed since * it is the one against which we will try to match records. *----------------------------------------------------------------*/ if ( m_poRelTable->SetFieldIndexed(0) == -1) return -1; return 0;}/********************************************************************** * TABRelation::GetFeature() * * Fill and return a TABFeature object for the specified feature id. * * The retuned pointer is a new TABFeature that will have to be freed * by the caller. * * Returns NULL if the specified feature id does not exist of if an * error happened. In any case, CPLError() will have been called to * report the reason of the failure. * * __TODO__ The current implementation fetches the features from each table * and creates a 3rd feature to merge them. There would be room for * optimization, at least by avoiding the duplication of the geometry * which can be big sometimes... but this would imply changes at the * lower-level in the lib. and we won't go there yet. **********************************************************************/TABFeature *TABRelation::GetFeature(int nFeatureId){ TABFeature *poMainFeature; TABFeature *poCurFeature; /*----------------------------------------------------------------- * Make sure init() has been called *----------------------------------------------------------------*/ if (m_poMainTable == NULL || m_poRelTable == NULL) { UGKError(ET_Failure, UGKErr_IllegalArg, "GetFeatureRef() failed: object not initialized yet!"); return NULL; } /*----------------------------------------------------------------- * Read main feature and create a new one of the right type *----------------------------------------------------------------*/ if ((poMainFeature = m_poMainTable->GetFeatureRef(nFeatureId)) == NULL) { // Feature cannot be read from main table... // an error has already been reported. return NULL; } poCurFeature = poMainFeature->CloneTABFeature(m_poDefn); /*----------------------------------------------------------------- * Keep track of FID and copy the geometry *----------------------------------------------------------------*/ poCurFeature->SetFID(nFeatureId); if (poCurFeature->GetFeatureClass() != TABFCNoGeomFeature) { UGKGeometry *poGeom; poGeom = poMainFeature->GetGeometryRef(); poCurFeature->SetGeometry(poGeom); } /*----------------------------------------------------------------- * Fetch feature from related table * * __TODO__ Right now we support only many-to-1 relationships, but * it might be possible to have several related entries * for a single key, and in this case we should return * one new feature for each of them. *----------------------------------------------------------------*/ TABFeature *poRelFeature=NULL; UGKByte *pKey = BuildFieldKey(poMainFeature, m_nMainFieldNo, m_poMainTable->GetNativeFieldType(m_nMainFieldNo), m_nRelFieldIndexNo); int i; int nRelFeatureId = m_poRelINDFileRef->FindFirst(m_nRelFieldIndexNo, pKey); if (nRelFeatureId > 0) poRelFeature = m_poRelTable->GetFeatureRef(nRelFeatureId); /*----------------------------------------------------------------- * Copy fields from poMainFeature *----------------------------------------------------------------*/ for(i=0; i<poMainFeature->GetFieldCount(); i++) { if (m_panMainTableFieldMap[i] != -1) { poCurFeature->SetField(m_panMainTableFieldMap[i], poMainFeature->GetRawFieldRef(i)); } } /*----------------------------------------------------------------- * Copy fields from poRelFeature... * * NOTE: For now, if no corresponding feature is found in RelTable * then we will just leave the corresponding fields unset. *----------------------------------------------------------------*/ for(i=0; poRelFeature && i<poRelFeature->GetFieldCount(); i++) { if (m_panRelTableFieldMap[i] != -1) { poCurFeature->SetField(m_panRelTableFieldMap[i], poRelFeature->GetRawFieldRef(i)); } } return poCurFeature;}/********************************************************************** * TABRelation::BuildFieldKey()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -