1 /******************************************************************************
2 * $Id: ogrwfsjoinlayer.cpp 29064 2015-04-30 08:04:34Z rouault $
3 *
4 * Project: WFS Translator
5 * Purpose: Implements OGRWFSJoinLayer class.
6 * Author: Even Rouault, <even dot rouault at spatialys dot com>
7 *
8 ******************************************************************************
9 * Copyright (c) 2015, Even Rouault <even dot rouault at spatialys dot com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "ogr_wfs.h"
31 #include "../../frmts/wms/md5.h"
32
33 CPL_CVSID("$Id: ogrwfsjoinlayer.cpp 29064 2015-04-30 08:04:34Z rouault $");
34
35 /************************************************************************/
36 /* OGRWFSJoinLayer() */
37 /************************************************************************/
38
OGRWFSJoinLayer(OGRWFSDataSource * poDS,const swq_select * psSelectInfo,const CPLString & osGlobalFilter)39 OGRWFSJoinLayer::OGRWFSJoinLayer(OGRWFSDataSource* poDS,
40 const swq_select* psSelectInfo,
41 const CPLString& osGlobalFilter)
42 {
43 this->poDS = poDS;
44 this->osGlobalFilter = osGlobalFilter;
45 poFeatureDefn = NULL;
46 bPagingActive = FALSE;
47 nPagingStartIndex = 0;
48 nFeatureRead = 0;
49 nFeatureCountRequested = 0;
50 poBaseDS = NULL;
51 poBaseLayer = NULL;
52 bReloadNeeded = FALSE;
53 bHasFetched = FALSE;
54 bDistinct = (psSelectInfo->query_mode == SWQM_DISTINCT_LIST);
55
56 CPLString osName("join_");
57 CPLString osLayerName;
58 osLayerName = psSelectInfo->table_defs[0].table_name;
59 apoLayers.push_back((OGRWFSLayer*)poDS->GetLayerByName(osLayerName));
60 osName += osLayerName;
61 for(int i=0;i<psSelectInfo->join_count;i++)
62 {
63 osName += "_";
64 osLayerName = psSelectInfo->table_defs[
65 psSelectInfo->join_defs[i].secondary_table].table_name;
66 apoLayers.push_back((OGRWFSLayer*)poDS->GetLayerByName(osLayerName));
67 osName += osLayerName;
68 }
69
70 osFeatureTypes = "(";
71 for(int i=0;i<(int)apoLayers.size();i++)
72 {
73 if( i > 0 )
74 osFeatureTypes += ",";
75 osFeatureTypes += apoLayers[i]->GetName();
76 }
77 osFeatureTypes += ")";
78
79 SetDescription(osName);
80
81 poFeatureDefn = new OGRFeatureDefn(GetDescription());
82 poFeatureDefn->Reference();
83 poFeatureDefn->SetGeomType(wkbNone);
84
85 for( int i = 0; i < psSelectInfo->result_columns; i++ )
86 {
87 swq_col_def *def = psSelectInfo->column_defs + i;
88 int table_index;
89 if( def->table_index >= 0 )
90 table_index = def->table_index;
91 else
92 {
93 CPLAssert(def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST);
94 table_index = def->expr->papoSubExpr[0]->table_index;
95 }
96 OGRWFSLayer* poLayer = apoLayers[table_index];
97 const char* pszTableAlias = psSelectInfo->table_defs[table_index].table_alias;
98 const char* pszTablePrefix = pszTableAlias ? pszTableAlias : poLayer->GetShortName();
99 int idx = poLayer->GetLayerDefn()->GetFieldIndex(def->field_name);
100 if( idx >= 0 )
101 {
102 OGRFieldDefn oFieldDefn(poLayer->GetLayerDefn()->GetFieldDefn(idx));
103 const char* pszSrcFieldname = CPLSPrintf("%s.%s",
104 poLayer->GetShortName(),
105 oFieldDefn.GetNameRef());
106 const char* pszFieldname = CPLSPrintf("%s.%s",
107 pszTablePrefix,
108 oFieldDefn.GetNameRef());
109 aoSrcFieldNames.push_back(pszSrcFieldname);
110 oFieldDefn.SetName(def->field_alias ? def->field_alias : pszFieldname);
111 if( def->expr && def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST)
112 {
113 switch( def->field_type )
114 {
115 case SWQ_INTEGER: oFieldDefn.SetType(OFTInteger); break;
116 case SWQ_INTEGER64: oFieldDefn.SetType(OFTInteger64); break;
117 case SWQ_FLOAT: oFieldDefn.SetType(OFTReal); break;
118 case SWQ_STRING: oFieldDefn.SetType(OFTString); break;
119 case SWQ_BOOLEAN: oFieldDefn.SetType(OFTInteger); oFieldDefn.SetSubType(OFSTBoolean); break;
120 case SWQ_DATE: oFieldDefn.SetType(OFTDate); break;
121 case SWQ_TIME: oFieldDefn.SetType(OFTTime); break;
122 case SWQ_TIMESTAMP: oFieldDefn.SetType(OFTDateTime); break;
123 default: break;
124 }
125 }
126 poFeatureDefn->AddFieldDefn(&oFieldDefn);
127 }
128 else
129 {
130 idx = poLayer->GetLayerDefn()->GetGeomFieldIndex(def->field_name);
131 if (idx >= 0 )
132 {
133 OGRGeomFieldDefn oFieldDefn(poLayer->GetLayerDefn()->GetGeomFieldDefn(idx));
134 const char* pszSrcFieldname = CPLSPrintf("%s.%s",
135 poLayer->GetShortName(),
136 oFieldDefn.GetNameRef());
137 const char* pszFieldname = CPLSPrintf("%s.%s",
138 pszTablePrefix,
139 oFieldDefn.GetNameRef());
140 aoSrcGeomFieldNames.push_back(pszSrcFieldname);
141 oFieldDefn.SetName(def->field_alias ? def->field_alias : pszFieldname);
142 poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
143 }
144 }
145 }
146
147 for(int i=0;i<psSelectInfo->order_specs;i++)
148 {
149 int nFieldIndex = apoLayers[0]->GetLayerDefn()->GetFieldIndex(
150 psSelectInfo->order_defs[i].field_name);
151 if (nFieldIndex < 0)
152 break;
153
154 /* Make sure to have the right case */
155 const char* pszFieldName = apoLayers[0]->GetLayerDefn()->
156 GetFieldDefn(nFieldIndex)->GetNameRef();
157 if( osSortBy.size() )
158 osSortBy += ",";
159 osSortBy += pszFieldName;
160 if( !psSelectInfo->order_defs[i].ascending_flag )
161 osSortBy += " DESC";
162 }
163
164 CPLXMLNode* psGlobalSchema = CPLCreateXMLNode( NULL, CXT_Element, "Schema" );
165 for(int i=0;i<(int)apoLayers.size();i++)
166 {
167 CPLString osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", apoLayers[i]);
168 CPLPushErrorHandler(CPLQuietErrorHandler);
169 CPLXMLNode* psSchema = CPLParseXMLFile(osTmpFileName);
170 CPLPopErrorHandler();
171 if( psSchema == NULL )
172 {
173 CPLDestroyXMLNode(psGlobalSchema);
174 psGlobalSchema = NULL;
175 break;
176 }
177 CPLXMLNode* psIter;
178 for(psIter = psSchema->psChild; psIter != NULL; psIter = psIter->psNext )
179 {
180 if( psIter->eType == CXT_Element )
181 break;
182 }
183 CPLAddXMLChild(psGlobalSchema, CPLCloneXMLTree(psIter));
184 CPLDestroyXMLNode(psSchema);
185 }
186 if( psGlobalSchema )
187 {
188 CPLString osTmpFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
189 CPLSerializeXMLTreeToFile(psGlobalSchema, osTmpFileName);
190 CPLDestroyXMLNode(psGlobalSchema);
191 }
192 }
193
194 /************************************************************************/
195 /* ~OGRWFSJoinLayer() */
196 /************************************************************************/
197
~OGRWFSJoinLayer()198 OGRWFSJoinLayer::~OGRWFSJoinLayer()
199 {
200 if( poFeatureDefn != NULL )
201 poFeatureDefn->Release();
202 if( poBaseDS != NULL )
203 GDALClose(poBaseDS);
204
205 CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
206 OGRWFSRecursiveUnlink(osTmpDirName);
207 }
208
209 /************************************************************************/
210 /* OGRWFSRemoveReferenceToTableAlias() */
211 /************************************************************************/
212
OGRWFSRemoveReferenceToTableAlias(swq_expr_node * poNode,const swq_select * psSelectInfo)213 static void OGRWFSRemoveReferenceToTableAlias(swq_expr_node* poNode,
214 const swq_select* psSelectInfo)
215 {
216 if( poNode->eNodeType == SNT_COLUMN )
217 {
218 if( poNode->table_name != NULL )
219 {
220 for(int i=0;i < psSelectInfo->table_count;i++)
221 {
222 if( psSelectInfo->table_defs[i].table_alias != NULL &&
223 EQUAL(poNode->table_name, psSelectInfo->table_defs[i].table_alias) )
224 {
225 CPLFree(poNode->table_name);
226 poNode->table_name = CPLStrdup(psSelectInfo->table_defs[i].table_name);
227 break;
228 }
229 }
230 }
231 }
232 else if( poNode->eNodeType == SNT_OPERATION )
233 {
234 for(int i=0;i < poNode->nSubExprCount;i++)
235 OGRWFSRemoveReferenceToTableAlias(poNode->papoSubExpr[i],
236 psSelectInfo);
237 }
238 }
239
240 /************************************************************************/
241 /* Build() */
242 /************************************************************************/
243
Build(OGRWFSDataSource * poDS,const swq_select * psSelectInfo)244 OGRWFSJoinLayer* OGRWFSJoinLayer::Build(OGRWFSDataSource* poDS,
245 const swq_select* psSelectInfo)
246 {
247 CPLString osGlobalFilter;
248
249 for( int i = 0; i < psSelectInfo->result_columns; i++ )
250 {
251 swq_col_def *def = psSelectInfo->column_defs + i;
252 if( !(def->col_func == SWQCF_NONE &&
253 (def->expr == NULL ||
254 def->expr->eNodeType == SNT_COLUMN ||
255 (def->expr->eNodeType == SNT_OPERATION && def->expr->nOperation == SWQ_CAST))) )
256 {
257 CPLError(CE_Failure, CPLE_NotSupported,
258 "Only column names supported in column selection");
259 return NULL;
260 }
261 }
262
263 if( psSelectInfo->join_count > 1 || psSelectInfo->where_expr != NULL )
264 osGlobalFilter += "<And>";
265 for(int i=0;i<psSelectInfo->join_count;i++)
266 {
267 OGRWFSRemoveReferenceToTableAlias(psSelectInfo->join_defs[i].poExpr,
268 psSelectInfo);
269 int bOutNeedsNullCheck;
270 CPLString osFilter = WFS_TurnSQLFilterToOGCFilter(
271 psSelectInfo->join_defs[i].poExpr,
272 poDS,
273 NULL,
274 200,
275 TRUE, /* bPropertyIsNotEqualToSupported */
276 FALSE, /* bUseFeatureId */
277 FALSE, /* bGmlObjectIdNeedsGMLPrefix */
278 "",
279 &bOutNeedsNullCheck);
280 if( osFilter.size() == 0 )
281 {
282 CPLError(CE_Failure, CPLE_NotSupported,
283 "Unsupported JOIN clause");
284 return NULL;
285 }
286 osGlobalFilter += osFilter;
287 }
288 if( psSelectInfo->where_expr != NULL )
289 {
290 OGRWFSRemoveReferenceToTableAlias(psSelectInfo->where_expr,
291 psSelectInfo);
292 int bOutNeedsNullCheck;
293 CPLString osFilter = WFS_TurnSQLFilterToOGCFilter(
294 psSelectInfo->where_expr,
295 poDS,
296 NULL,
297 200,
298 TRUE, /* bPropertyIsNotEqualToSupported */
299 FALSE, /* bUseFeatureId */
300 FALSE, /* bGmlObjectIdNeedsGMLPrefix */
301 "",
302 &bOutNeedsNullCheck);
303 if( osFilter.size() == 0 )
304 {
305 CPLError(CE_Failure, CPLE_NotSupported,
306 "Unsupported WHERE clause");
307 return NULL;
308 }
309 osGlobalFilter += osFilter;
310 }
311 if( psSelectInfo->join_count > 1 || psSelectInfo->where_expr != NULL )
312 osGlobalFilter += "</And>";
313 CPLDebug("WFS", "osGlobalFilter = %s", osGlobalFilter.c_str());
314
315 OGRWFSJoinLayer* poLayer = new OGRWFSJoinLayer(poDS, psSelectInfo,
316 osGlobalFilter);
317 return poLayer;
318 }
319
320 /************************************************************************/
321 /* ResetReading() */
322 /************************************************************************/
323
ResetReading()324 void OGRWFSJoinLayer::ResetReading()
325 {
326 if (bPagingActive)
327 bReloadNeeded = TRUE;
328 nPagingStartIndex = 0;
329 nFeatureRead = 0;
330 nFeatureCountRequested = 0;
331 if (bReloadNeeded)
332 {
333 GDALClose(poBaseDS);
334 poBaseDS = NULL;
335 poBaseLayer = NULL;
336 bHasFetched = FALSE;
337 bReloadNeeded = FALSE;
338 }
339 if (poBaseLayer)
340 poBaseLayer->ResetReading();
341 aoSetMD5.clear();
342 }
343
344 /************************************************************************/
345 /* MakeGetFeatureURL() */
346 /************************************************************************/
347
MakeGetFeatureURL(int bRequestHits)348 CPLString OGRWFSJoinLayer::MakeGetFeatureURL(int bRequestHits)
349 {
350 CPLString osURL(poDS->GetBaseURL());
351 osURL = CPLURLAddKVP(osURL, "SERVICE", "WFS");
352 osURL = CPLURLAddKVP(osURL, "VERSION", poDS->GetVersion());
353 osURL = CPLURLAddKVP(osURL, "REQUEST", "GetFeature");
354 osURL = CPLURLAddKVP(osURL, "TYPENAMES", WFS_EscapeURL(osFeatureTypes));
355
356 int nRequestMaxFeatures = 0;
357 if (poDS->IsPagingAllowed() && !bRequestHits &&
358 CPLURLGetValue(osURL, "COUNT").size() == 0 )
359 {
360 osURL = CPLURLAddKVP(osURL, "STARTINDEX",
361 CPLSPrintf("%d", nPagingStartIndex +
362 poDS->GetBaseStartIndex()));
363 nRequestMaxFeatures = poDS->GetPageSize();
364 nFeatureCountRequested = nRequestMaxFeatures;
365 bPagingActive = TRUE;
366 }
367
368 if (nRequestMaxFeatures)
369 {
370 osURL = CPLURLAddKVP(osURL,
371 "COUNT",
372 CPLSPrintf("%d", nRequestMaxFeatures));
373 }
374
375 CPLString osFilter;
376 osFilter = "<Filter xmlns=\"http://www.opengis.net/fes/2.0\"";
377
378 std::map<CPLString, CPLString> oMapNS;
379 for(int i=0;i<(int)apoLayers.size();i++)
380 {
381 const char* pszNS = apoLayers[i]->GetNamespacePrefix();
382 const char* pszNSVal = apoLayers[i]->GetNamespaceName();
383 if( pszNS && pszNSVal )
384 oMapNS[pszNS] = pszNSVal;
385 }
386 std::map<CPLString, CPLString>::iterator oIter = oMapNS.begin();
387 for(; oIter != oMapNS.end(); ++oIter )
388 {
389 osFilter += " xmlns:";
390 osFilter += oIter->first;
391 osFilter += "=\"";
392 osFilter += oIter->second;
393 osFilter += "\"";
394 }
395 osFilter += " xmlns:gml=\"http://www.opengis.net/gml/3.2\">";
396 osFilter += osGlobalFilter;
397 osFilter += "</Filter>";
398
399 osURL = CPLURLAddKVP(osURL, "FILTER", WFS_EscapeURL(osFilter));
400
401 if (bRequestHits)
402 {
403 osURL = CPLURLAddKVP(osURL, "RESULTTYPE", "hits");
404 }
405 else if( osSortBy.size() )
406 {
407 osURL = CPLURLAddKVP(osURL, "SORTBY", WFS_EscapeURL(osSortBy));
408 }
409
410 return osURL;
411 }
412
413 /************************************************************************/
414 /* FetchGetFeature() */
415 /************************************************************************/
416
FetchGetFeature()417 GDALDataset* OGRWFSJoinLayer::FetchGetFeature()
418 {
419
420 CPLString osURL = MakeGetFeatureURL();
421 CPLDebug("WFS", "%s", osURL.c_str());
422
423 CPLHTTPResult* psResult = NULL;
424
425 /* Try streaming when the output format is GML and that we have a .xsd */
426 /* that we are able to understand */
427 CPLString osXSDFileName = CPLSPrintf("/vsimem/tempwfs_%p/file.xsd", this);
428 VSIStatBufL sBuf;
429 if (CSLTestBoolean(CPLGetConfigOption("OGR_WFS_USE_STREAMING", "YES")) &&
430 VSIStatL(osXSDFileName, &sBuf) == 0 && GDALGetDriverByName("GML") != NULL)
431 {
432 const char* pszStreamingName = CPLSPrintf("/vsicurl_streaming/%s",
433 osURL.c_str());
434 if( strncmp(osURL, "/vsimem/", strlen("/vsimem/")) == 0 &&
435 CSLTestBoolean(CPLGetConfigOption("CPL_CURL_ENABLE_VSIMEM", "FALSE")) )
436 {
437 pszStreamingName = osURL.c_str();
438 }
439
440 const char* const apszAllowedDrivers[] = { "GML", NULL };
441 const char* apszOpenOptions[2] = { NULL, NULL };
442 apszOpenOptions[0] = CPLSPrintf("XSD=%s", osXSDFileName.c_str());
443 GDALDataset* poGML_DS = (GDALDataset*)
444 GDALOpenEx(pszStreamingName, GDAL_OF_VECTOR, apszAllowedDrivers,
445 apszOpenOptions, NULL);
446 if (poGML_DS)
447 {
448 //bStreamingDS = TRUE;
449 return poGML_DS;
450 }
451
452 /* In case of failure, read directly the content to examine */
453 /* it, if it is XML error content */
454 char szBuffer[2048];
455 int nRead = 0;
456 VSILFILE* fp = VSIFOpenL(pszStreamingName, "rb");
457 if (fp)
458 {
459 nRead = (int)VSIFReadL(szBuffer, 1, sizeof(szBuffer) - 1, fp);
460 szBuffer[nRead] = '\0';
461 VSIFCloseL(fp);
462 }
463
464 if (nRead != 0)
465 {
466 if (strstr(szBuffer, "<ServiceExceptionReport") != NULL ||
467 strstr(szBuffer, "<ows:ExceptionReport") != NULL)
468 {
469 CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
470 szBuffer);
471 return NULL;
472 }
473 }
474 }
475
476 //bStreamingDS = FALSE;
477 psResult = poDS->HTTPFetch( osURL, NULL);
478 if (psResult == NULL)
479 {
480 return NULL;
481 }
482
483 CPLString osTmpDirName = CPLSPrintf("/vsimem/tempwfs_%p", this);
484 VSIMkdir(osTmpDirName, 0);
485
486 GByte *pabyData = psResult->pabyData;
487 int nDataLen = psResult->nDataLen;
488
489 if (strstr((const char*)pabyData, "<ServiceExceptionReport") != NULL ||
490 strstr((const char*)pabyData, "<ows:ExceptionReport") != NULL)
491 {
492 CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
493 pabyData);
494 CPLHTTPDestroyResult(psResult);
495 return NULL;
496 }
497
498 CPLString osTmpFileName;
499
500 osTmpFileName = osTmpDirName + "/file.gfs";
501 VSIUnlink(osTmpFileName);
502
503 osTmpFileName = osTmpDirName + "/file.gml";
504
505 VSILFILE *fp = VSIFileFromMemBuffer( osTmpFileName, pabyData,
506 nDataLen, TRUE);
507 VSIFCloseL(fp);
508 psResult->pabyData = NULL;
509
510 CPLHTTPDestroyResult(psResult);
511
512 OGRDataSource* poDS;
513
514 poDS = (OGRDataSource*) OGROpen(osTmpFileName, FALSE, NULL);
515 if (poDS == NULL)
516 {
517 if( strstr((const char*)pabyData, "<wfs:FeatureCollection") == NULL &&
518 strstr((const char*)pabyData, "<gml:FeatureCollection") == NULL)
519 {
520 if (nDataLen > 1000)
521 pabyData[1000] = 0;
522 CPLError(CE_Failure, CPLE_AppDefined,
523 "Error: cannot parse %s", pabyData);
524 }
525 return NULL;
526 }
527
528 OGRLayer* poLayer = poDS->GetLayer(0);
529 if (poLayer == NULL)
530 {
531 OGRDataSource::DestroyDataSource(poDS);
532 return NULL;
533 }
534
535 return poDS;
536 }
537
538 /************************************************************************/
539 /* GetNextFeature() */
540 /************************************************************************/
541
GetNextFeature()542 OGRFeature* OGRWFSJoinLayer::GetNextFeature()
543 {
544 while(TRUE)
545 {
546 if (bPagingActive && nFeatureRead == nPagingStartIndex + nFeatureCountRequested)
547 {
548 bReloadNeeded = TRUE;
549 nPagingStartIndex = nFeatureRead;
550 }
551 if (bReloadNeeded)
552 {
553 GDALClose(poBaseDS);
554 poBaseDS = NULL;
555 poBaseLayer = NULL;
556 bHasFetched = FALSE;
557 bReloadNeeded = FALSE;
558 }
559 if (poBaseDS == NULL && !bHasFetched)
560 {
561 bHasFetched = TRUE;
562 poBaseDS = FetchGetFeature();
563 if (poBaseDS)
564 {
565 poBaseLayer = poBaseDS->GetLayer(0);
566 poBaseLayer->ResetReading();
567 }
568 }
569 if (!poBaseLayer)
570 return NULL;
571
572 OGRFeature* poSrcFeature = poBaseLayer->GetNextFeature();
573 if (poSrcFeature == NULL)
574 return NULL;
575 nFeatureRead ++;
576
577 OGRFeature* poNewFeature = new OGRFeature(poFeatureDefn);
578
579 struct cvs_MD5Context sMD5Context;
580 if( bDistinct )
581 cvs_MD5Init(&sMD5Context);
582
583 for(int i=0;i<(int)aoSrcFieldNames.size();i++)
584 {
585 int iSrcField = poSrcFeature->GetFieldIndex(aoSrcFieldNames[i]);
586 if( iSrcField >= 0 && poSrcFeature->IsFieldSet(iSrcField) )
587 {
588 OGRFieldType eType = poFeatureDefn->GetFieldDefn(i)->GetType();
589 if( eType == poSrcFeature->GetFieldDefnRef(iSrcField)->GetType() )
590 {
591 poNewFeature->SetField(i, poSrcFeature->GetRawFieldRef(iSrcField));
592 }
593 else if( eType == OFTString )
594 poNewFeature->SetField(i, poSrcFeature->GetFieldAsString(iSrcField));
595 else if( eType == OFTInteger )
596 poNewFeature->SetField(i, poSrcFeature->GetFieldAsInteger(iSrcField));
597 else if( eType == OFTInteger64 )
598 poNewFeature->SetField(i, poSrcFeature->GetFieldAsInteger64(iSrcField));
599 else if( eType == OFTReal )
600 poNewFeature->SetField(i, poSrcFeature->GetFieldAsDouble(iSrcField));
601 else
602 poNewFeature->SetField(i, poSrcFeature->GetFieldAsString(iSrcField));
603 if( bDistinct )
604 {
605 if( eType == OFTInteger )
606 {
607 int nVal = poNewFeature->GetFieldAsInteger(i);
608 cvs_MD5Update( &sMD5Context, (const GByte*)&nVal, sizeof(nVal));
609 }
610 else if( eType == OFTInteger64 )
611 {
612 GIntBig nVal = poNewFeature->GetFieldAsInteger64(i);
613 cvs_MD5Update( &sMD5Context, (const GByte*)&nVal, sizeof(nVal));
614 }
615 else if( eType == OFTReal )
616 {
617 double dfVal = poNewFeature->GetFieldAsDouble(i);
618 cvs_MD5Update( &sMD5Context, (const GByte*)&dfVal, sizeof(dfVal));
619 }
620 else
621 {
622 const char* pszStr = poNewFeature->GetFieldAsString(i);
623 cvs_MD5Update( &sMD5Context, (const GByte*)pszStr, strlen(pszStr));
624 }
625 }
626 }
627 }
628 for(int i=0;i<(int)aoSrcGeomFieldNames.size();i++)
629 {
630 int iSrcField = poSrcFeature->GetGeomFieldIndex(aoSrcGeomFieldNames[i]);
631 if( iSrcField >= 0)
632 {
633 OGRGeometry* poGeom = poSrcFeature->StealGeometry(iSrcField);
634 if( poGeom )
635 {
636 poGeom->assignSpatialReference(poFeatureDefn->GetGeomFieldDefn(i)->GetSpatialRef());
637 poNewFeature->SetGeomFieldDirectly(i, poGeom);
638
639 if( bDistinct )
640 {
641 int nSize = poGeom->WkbSize();
642 GByte* pabyGeom = (GByte*)CPLMalloc(nSize);
643 poGeom->exportToWkb(wkbNDR, pabyGeom);
644 cvs_MD5Update( &sMD5Context, (const GByte*)pabyGeom, nSize);
645 CPLFree(pabyGeom);
646 }
647 }
648 }
649 }
650
651 poNewFeature->SetFID(nFeatureRead);
652 delete poSrcFeature;
653
654 if( bDistinct )
655 {
656 CPLString osDigest = "0123456789abcdef";
657 cvs_MD5Final((unsigned char*)osDigest.c_str(), &sMD5Context);
658 if( aoSetMD5.find(osDigest) == aoSetMD5.end() )
659 {
660 aoSetMD5.insert(osDigest);
661 return poNewFeature;
662 }
663 else
664 delete poNewFeature;
665 }
666 else
667 return poNewFeature;
668 }
669 }
670
671 /************************************************************************/
672 /* ExecuteGetFeatureResultTypeHits() */
673 /************************************************************************/
674
ExecuteGetFeatureResultTypeHits()675 GIntBig OGRWFSJoinLayer::ExecuteGetFeatureResultTypeHits()
676 {
677 char* pabyData = NULL;
678 CPLString osURL = MakeGetFeatureURL(TRUE);
679 CPLDebug("WFS", "%s", osURL.c_str());
680
681 CPLHTTPResult* psResult = poDS->HTTPFetch( osURL, NULL);
682 if (psResult == NULL)
683 {
684 return -1;
685 }
686
687 pabyData = (char*) psResult->pabyData;
688 psResult->pabyData = NULL;
689
690 if (strstr(pabyData, "<ServiceExceptionReport") != NULL ||
691 strstr(pabyData, "<ows:ExceptionReport") != NULL)
692 {
693 CPLError(CE_Failure, CPLE_AppDefined, "Error returned by server : %s",
694 pabyData);
695 CPLHTTPDestroyResult(psResult);
696 CPLFree(pabyData);
697 return -1;
698 }
699
700 CPLXMLNode* psXML = CPLParseXMLString( pabyData );
701 if (psXML == NULL)
702 {
703 CPLError(CE_Failure, CPLE_AppDefined, "Invalid XML content : %s",
704 pabyData);
705 CPLHTTPDestroyResult(psResult);
706 CPLFree(pabyData);
707 return -1;
708 }
709
710 CPLStripXMLNamespace( psXML, NULL, TRUE );
711 CPLXMLNode* psRoot = CPLGetXMLNode( psXML, "=FeatureCollection" );
712 if (psRoot == NULL)
713 {
714 CPLError(CE_Failure, CPLE_AppDefined, "Cannot find <FeatureCollection>");
715 CPLDestroyXMLNode( psXML );
716 CPLHTTPDestroyResult(psResult);
717 CPLFree(pabyData);
718 return -1;
719 }
720
721 const char* pszValue = CPLGetXMLValue(psRoot, "numberMatched", NULL); /* WFS 2.0.0 */
722 if (pszValue == NULL)
723 {
724 CPLError(CE_Failure, CPLE_AppDefined, "Cannot find numberMatched");
725 CPLDestroyXMLNode( psXML );
726 CPLHTTPDestroyResult(psResult);
727 CPLFree(pabyData);
728 return -1;
729 }
730
731 GIntBig nFeatures = CPLAtoGIntBig(pszValue);
732
733 CPLDestroyXMLNode( psXML );
734 CPLHTTPDestroyResult(psResult);
735 CPLFree(pabyData);
736
737 return nFeatures;
738 }
739
740 /************************************************************************/
741 /* GetFeatureCount() */
742 /************************************************************************/
743
GetFeatureCount(int bForce)744 GIntBig OGRWFSJoinLayer::GetFeatureCount( int bForce )
745 {
746 GIntBig nFeatures;
747
748 if( !bDistinct )
749 {
750 nFeatures = ExecuteGetFeatureResultTypeHits();
751 if (nFeatures >= 0)
752 return nFeatures;
753 }
754
755 nFeatures = OGRLayer::GetFeatureCount(bForce);
756 return nFeatures;
757 }
758
759 /************************************************************************/
760 /* GetLayerDefn() */
761 /************************************************************************/
762
GetLayerDefn()763 OGRFeatureDefn* OGRWFSJoinLayer::GetLayerDefn()
764 {
765 return poFeatureDefn;
766 }
767
768 /************************************************************************/
769 /* TestCapability() */
770 /************************************************************************/
771
TestCapability(const char *)772 int OGRWFSJoinLayer::TestCapability( const char * )
773 {
774 return FALSE;
775 }
776
777 /************************************************************************/
778 /* SetSpatialFilter() */
779 /************************************************************************/
780
SetSpatialFilter(OGRGeometry * poGeom)781 void OGRWFSJoinLayer::SetSpatialFilter( OGRGeometry * poGeom )
782 {
783 if( poGeom != NULL )
784 CPLError(CE_Failure, CPLE_NotSupported,
785 "Setting a spatial filter on a layer resulting from a WFS join is unsupported");
786 }
787
788 /************************************************************************/
789 /* SetAttributeFilter() */
790 /************************************************************************/
791
SetAttributeFilter(const char * pszFilter)792 OGRErr OGRWFSJoinLayer::SetAttributeFilter( const char *pszFilter )
793 {
794 if( pszFilter != NULL )
795 {
796 CPLError(CE_Failure, CPLE_NotSupported,
797 "Setting an attribute filter on a layer resulting from a WFS join is unsupported");
798 return OGRERR_FAILURE;
799 }
800 return OGRERR_NONE;
801 }
802