1 : /******************************************************************************
2 : * $Id: ogrpgdumpdatasource.cpp 24950 2012-09-22 13:54:36Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implements OGRPGDumpDataSource class.
6 : * Author: Even Rouault, <even dot rouault at mines dash paris dot org>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2010, Even Rouault
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 <string.h>
31 : #include "ogr_pgdump.h"
32 : #include "cpl_conv.h"
33 : #include "cpl_string.h"
34 :
35 : CPL_CVSID("$Id: ogrpgdumpdatasource.cpp 24950 2012-09-22 13:54:36Z rouault $");
36 :
37 : /************************************************************************/
38 : /* OGRPGDumpDataSource() */
39 : /************************************************************************/
40 :
41 3 : OGRPGDumpDataSource::OGRPGDumpDataSource(const char* pszName,
42 3 : char** papszOptions)
43 :
44 : {
45 3 : nLayers = 0;
46 3 : papoLayers = NULL;
47 3 : this->pszName = CPLStrdup(pszName);
48 3 : bTriedOpen = FALSE;
49 3 : fp = NULL;
50 3 : bInTransaction = FALSE;
51 3 : poLayerInCopyMode = NULL;
52 :
53 3 : const char *pszCRLFFormat = CSLFetchNameValue( papszOptions, "LINEFORMAT");
54 :
55 : int bUseCRLF;
56 3 : if( pszCRLFFormat == NULL )
57 : {
58 : #ifdef WIN32
59 : bUseCRLF = TRUE;
60 : #else
61 1 : bUseCRLF = FALSE;
62 : #endif
63 : }
64 2 : else if( EQUAL(pszCRLFFormat,"CRLF") )
65 1 : bUseCRLF = TRUE;
66 1 : else if( EQUAL(pszCRLFFormat,"LF") )
67 1 : bUseCRLF = FALSE;
68 : else
69 : {
70 : CPLError( CE_Warning, CPLE_AppDefined,
71 : "LINEFORMAT=%s not understood, use one of CRLF or LF.",
72 0 : pszCRLFFormat );
73 : #ifdef WIN32
74 : bUseCRLF = TRUE;
75 : #else
76 0 : bUseCRLF = FALSE;
77 : #endif
78 : }
79 3 : pszEOL = (bUseCRLF) ? "\r\n" : "\n";
80 3 : }
81 :
82 : /************************************************************************/
83 : /* ~OGRPGDumpDataSource() */
84 : /************************************************************************/
85 :
86 3 : OGRPGDumpDataSource::~OGRPGDumpDataSource()
87 :
88 : {
89 : int i;
90 :
91 3 : if (fp)
92 : {
93 3 : Commit();
94 3 : VSIFCloseL(fp);
95 3 : fp = NULL;
96 : }
97 :
98 6 : for(i=0;i<nLayers;i++)
99 3 : delete papoLayers[i];
100 3 : CPLFree(papoLayers);
101 3 : CPLFree(pszName);
102 3 : }
103 :
104 : /************************************************************************/
105 : /* StartTransaction() */
106 : /************************************************************************/
107 :
108 3 : void OGRPGDumpDataSource::StartTransaction()
109 : {
110 3 : if (bInTransaction)
111 0 : return;
112 3 : bInTransaction = TRUE;
113 3 : Log("BEGIN");
114 : }
115 :
116 : /************************************************************************/
117 : /* Commit() */
118 : /************************************************************************/
119 :
120 6 : void OGRPGDumpDataSource::Commit()
121 : {
122 6 : EndCopy();
123 :
124 6 : if (!bInTransaction)
125 3 : return;
126 3 : bInTransaction = FALSE;
127 3 : Log("COMMIT");
128 : }
129 :
130 : /************************************************************************/
131 : /* LaunderName() */
132 : /************************************************************************/
133 :
134 16 : char *OGRPGDumpDataSource::LaunderName( const char *pszSrcName )
135 :
136 : {
137 16 : char *pszSafeName = CPLStrdup( pszSrcName );
138 :
139 118 : for( int i = 0; pszSafeName[i] != '\0'; i++ )
140 : {
141 102 : pszSafeName[i] = (char) tolower( pszSafeName[i] );
142 102 : if( pszSafeName[i] == '\'' || pszSafeName[i] == '-' || pszSafeName[i] == '#' )
143 0 : pszSafeName[i] = '_';
144 : }
145 :
146 16 : if( strcmp(pszSrcName,pszSafeName) != 0 )
147 : CPLDebug("PG","LaunderName('%s') -> '%s'",
148 13 : pszSrcName, pszSafeName);
149 :
150 16 : return pszSafeName;
151 : }
152 :
153 : /************************************************************************/
154 : /* CreateLayer() */
155 : /************************************************************************/
156 :
157 : OGRLayer *
158 3 : OGRPGDumpDataSource::CreateLayer( const char * pszLayerName,
159 : OGRSpatialReference *poSRS,
160 : OGRwkbGeometryType eType,
161 : char ** papszOptions )
162 :
163 : {
164 3 : CPLString osCommand;
165 3 : const char *pszGeomType = NULL;
166 3 : char *pszTableName = NULL;
167 3 : char *pszSchemaName = NULL;
168 3 : int nDimension = 3;
169 3 : int bHavePostGIS = TRUE;
170 :
171 3 : const char* pszFIDColumnName = CSLFetchNameValue(papszOptions, "FID");
172 3 : CPLString osFIDColumnName;
173 3 : if (pszFIDColumnName == NULL)
174 3 : osFIDColumnName = "OGC_FID";
175 : else
176 : {
177 0 : if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
178 : {
179 0 : char* pszLaunderedFid = LaunderName(pszFIDColumnName);
180 0 : osFIDColumnName += OGRPGDumpEscapeColumnName(pszLaunderedFid);
181 0 : CPLFree(pszLaunderedFid);
182 : }
183 : else
184 0 : osFIDColumnName += OGRPGDumpEscapeColumnName(pszFIDColumnName);
185 : }
186 3 : pszFIDColumnName = osFIDColumnName.c_str();
187 :
188 3 : if (strncmp(pszLayerName, "pg", 2) == 0)
189 : {
190 : CPLError(CE_Warning, CPLE_AppDefined,
191 0 : "The layer name should not begin by 'pg' as it is a reserved prefix");
192 : }
193 :
194 : //bHavePostGIS = CSLFetchBoolean(papszOptions,"POSTGIS", TRUE);
195 :
196 3 : int bCreateTable = CSLFetchBoolean(papszOptions,"CREATE_TABLE", TRUE);
197 3 : int bCreateSchema = CSLFetchBoolean(papszOptions,"CREATE_SCHEMA", TRUE);
198 3 : const char* pszDropTable = CSLFetchNameValueDef(papszOptions,"DROP_TABLE", "YES");
199 :
200 3 : if( wkbFlatten(eType) == eType )
201 3 : nDimension = 2;
202 :
203 3 : if( CSLFetchNameValue( papszOptions, "DIM") != NULL )
204 1 : nDimension = atoi(CSLFetchNameValue( papszOptions, "DIM"));
205 :
206 : /* Should we turn layers with None geometry type as Unknown/GEOMETRY */
207 : /* so they are still recorded in geometry_columns table ? (#4012) */
208 : int bNoneAsUnknown = CSLTestBoolean(CSLFetchNameValueDef(
209 3 : papszOptions, "NONE_AS_UNKNOWN", "NO"));
210 3 : if (bNoneAsUnknown && eType == wkbNone)
211 0 : eType = wkbUnknown;
212 3 : else if (eType == wkbNone)
213 1 : bHavePostGIS = FALSE;
214 :
215 : int bExtractSchemaFromLayerName = CSLTestBoolean(CSLFetchNameValueDef(
216 3 : papszOptions, "EXTRACT_SCHEMA_FROM_LAYER_NAME", "YES"));
217 :
218 : /* Postgres Schema handling:
219 : Extract schema name from input layer name or passed with -lco SCHEMA.
220 : Set layer name to "schema.table" or to "table" if schema == current_schema()
221 : Usage without schema name is backwards compatible
222 : */
223 3 : const char* pszDotPos = strstr(pszLayerName,".");
224 3 : if ( pszDotPos != NULL && bExtractSchemaFromLayerName )
225 : {
226 0 : int length = pszDotPos - pszLayerName;
227 0 : pszSchemaName = (char*)CPLMalloc(length+1);
228 0 : strncpy(pszSchemaName, pszLayerName, length);
229 0 : pszSchemaName[length] = '\0';
230 :
231 0 : if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
232 0 : pszTableName = LaunderName( pszDotPos + 1 ); //skip "."
233 : else
234 0 : pszTableName = CPLStrdup( pszDotPos + 1 ); //skip "."
235 : }
236 : else
237 : {
238 3 : pszSchemaName = NULL;
239 3 : if( CSLFetchBoolean(papszOptions,"LAUNDER", TRUE) )
240 3 : pszTableName = LaunderName( pszLayerName ); //skip "."
241 : else
242 0 : pszTableName = CPLStrdup( pszLayerName ); //skip "."
243 : }
244 :
245 3 : Commit();
246 :
247 : /* -------------------------------------------------------------------- */
248 : /* Set the default schema for the layers. */
249 : /* -------------------------------------------------------------------- */
250 3 : if( CSLFetchNameValue( papszOptions, "SCHEMA" ) != NULL )
251 : {
252 2 : CPLFree(pszSchemaName);
253 2 : pszSchemaName = CPLStrdup(CSLFetchNameValue( papszOptions, "SCHEMA" ));
254 2 : if (bCreateSchema)
255 : {
256 2 : osCommand.Printf("CREATE SCHEMA \"%s\"", pszSchemaName);
257 2 : Log(osCommand);
258 : }
259 : }
260 :
261 3 : if ( pszSchemaName == NULL)
262 : {
263 1 : pszSchemaName = CPLStrdup("public");
264 : }
265 :
266 : /* -------------------------------------------------------------------- */
267 : /* Do we already have this layer? */
268 : /* -------------------------------------------------------------------- */
269 : int iLayer;
270 :
271 3 : for( iLayer = 0; iLayer < nLayers; iLayer++ )
272 : {
273 0 : if( EQUAL(pszLayerName,papoLayers[iLayer]->GetLayerDefn()->GetName()) )
274 : {
275 : CPLError( CE_Failure, CPLE_AppDefined,
276 : "Layer %s already exists, CreateLayer failed.\n",
277 0 : pszLayerName );
278 0 : CPLFree( pszTableName );
279 0 : CPLFree( pszSchemaName );
280 0 : return NULL;
281 : }
282 : }
283 :
284 :
285 3 : if (bCreateTable && (EQUAL(pszDropTable, "YES") ||
286 : EQUAL(pszDropTable, "ON") ||
287 : EQUAL(pszDropTable, "TRUE") ||
288 : EQUAL(pszDropTable, "IF_EXISTS")))
289 : {
290 3 : if (EQUAL(pszDropTable, "IF_EXISTS"))
291 0 : osCommand.Printf("DROP TABLE IF EXISTS \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName );
292 : else
293 3 : osCommand.Printf("DROP TABLE \"%s\".\"%s\" CASCADE", pszSchemaName, pszTableName );
294 3 : Log(osCommand);
295 : }
296 :
297 : /* -------------------------------------------------------------------- */
298 : /* Handle the GEOM_TYPE option. */
299 : /* -------------------------------------------------------------------- */
300 3 : pszGeomType = CSLFetchNameValue( papszOptions, "GEOM_TYPE" );
301 3 : if( pszGeomType == NULL )
302 : {
303 3 : pszGeomType = "geometry";
304 : }
305 :
306 3 : if( !EQUAL(pszGeomType,"geometry") && !EQUAL(pszGeomType, "geography"))
307 : {
308 : CPLError( CE_Failure, CPLE_AppDefined,
309 : "GEOM_TYPE in PostGIS enabled databases must be 'geometry' or 'geography'.\n"
310 : "Creation of layer %s with GEOM_TYPE %s has failed.",
311 0 : pszLayerName, pszGeomType );
312 0 : CPLFree( pszTableName );
313 0 : CPLFree( pszSchemaName );
314 0 : return NULL;
315 : }
316 :
317 : /* -------------------------------------------------------------------- */
318 : /* Try to get the SRS Id of this spatial reference system, */
319 : /* adding tot the srs table if needed. */
320 : /* -------------------------------------------------------------------- */
321 3 : int nSRSId = -1;
322 :
323 3 : if( CSLFetchNameValue( papszOptions, "SRID") != NULL )
324 1 : nSRSId = atoi(CSLFetchNameValue( papszOptions, "SRID"));
325 : else
326 : {
327 2 : if (poSRS)
328 : {
329 0 : const char* pszAuthorityName = poSRS->GetAuthorityName(NULL);
330 0 : if( pszAuthorityName != NULL && EQUAL( pszAuthorityName, "EPSG" ) )
331 : {
332 : /* Assume the EPSG Id is the SRS ID. Might be a wrong guess ! */
333 0 : nSRSId = atoi( poSRS->GetAuthorityCode(NULL) );
334 : }
335 : else
336 : {
337 0 : const char* pszGeogCSName = poSRS->GetAttrValue("GEOGCS");
338 0 : if (pszGeogCSName != NULL && EQUAL(pszGeogCSName, "GCS_WGS_1984"))
339 0 : nSRSId = 4326;
340 : }
341 : }
342 : }
343 :
344 3 : CPLString osEscapedTableNameSingleQuote = OGRPGDumpEscapeString(pszTableName, -1, "");
345 3 : const char* pszEscapedTableNameSingleQuote = osEscapedTableNameSingleQuote.c_str();
346 :
347 3 : const char *pszGeometryType = OGRToOGCGeomType(eType);
348 :
349 3 : const char *pszGFldName = NULL;
350 3 : if( bHavePostGIS && !EQUAL(pszGeomType, "geography"))
351 : {
352 2 : if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
353 1 : pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
354 : else
355 1 : pszGFldName = "wkb_geometry";
356 :
357 : /* Sometimes there is an old cruft entry in the geometry_columns
358 : * table if things were not properly cleaned up before. We make
359 : * an effort to clean out such cruft.
360 : */
361 : osCommand.Printf(
362 : "DELETE FROM geometry_columns WHERE f_table_name = %s AND f_table_schema = '%s'",
363 2 : pszEscapedTableNameSingleQuote, pszSchemaName );
364 2 : if (bCreateTable)
365 2 : Log(osCommand);
366 : }
367 :
368 :
369 3 : StartTransaction();
370 :
371 : /* -------------------------------------------------------------------- */
372 : /* Create a basic table with the FID. Also include the */
373 : /* geometry if this is not a PostGIS enabled table. */
374 : /* -------------------------------------------------------------------- */
375 :
376 3 : CPLString osCreateTable;
377 : int bTemporary = CSLFetchNameValue( papszOptions, "TEMPORARY" ) != NULL &&
378 3 : CSLTestBoolean(CSLFetchNameValue( papszOptions, "TEMPORARY" ));
379 3 : if (bTemporary)
380 : {
381 0 : CPLFree(pszSchemaName);
382 0 : pszSchemaName = CPLStrdup("pg_temp_1");
383 0 : osCreateTable.Printf("CREATE TEMPORARY TABLE \"%s\"", pszTableName);
384 : }
385 : else
386 3 : osCreateTable.Printf("CREATE TABLE \"%s\".\"%s\"", pszSchemaName, pszTableName);
387 :
388 3 : if( !bHavePostGIS )
389 : {
390 1 : if (eType == wkbNone)
391 : osCommand.Printf(
392 : "%s ( "
393 : " %s SERIAL, "
394 : " CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
395 1 : osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
396 : else
397 : osCommand.Printf(
398 : "%s ( "
399 : " %s SERIAL, "
400 : " WKB_GEOMETRY %s, "
401 : " CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
402 0 : osCreateTable.c_str(), pszFIDColumnName, pszGeomType, pszTableName, pszFIDColumnName );
403 : }
404 2 : else if ( EQUAL(pszGeomType, "geography") )
405 : {
406 0 : if( CSLFetchNameValue( papszOptions, "GEOMETRY_NAME") != NULL )
407 0 : pszGFldName = CSLFetchNameValue( papszOptions, "GEOMETRY_NAME");
408 : else
409 0 : pszGFldName = "the_geog";
410 :
411 0 : if (nSRSId)
412 : osCommand.Printf(
413 : "%s ( %s SERIAL, \"%s\" geography(%s%s,%d), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
414 0 : osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", nSRSId, pszTableName, pszFIDColumnName );
415 : else
416 : osCommand.Printf(
417 : "%s ( %s SERIAL, \"%s\" geography(%s%s), CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
418 0 : osCreateTable.c_str(), pszFIDColumnName, pszGFldName, pszGeometryType, nDimension == 2 ? "" : "Z", pszTableName, pszFIDColumnName );
419 : }
420 : else
421 : {
422 : osCommand.Printf(
423 : "%s ( %s SERIAL, CONSTRAINT \"%s_pk\" PRIMARY KEY (%s) )",
424 2 : osCreateTable.c_str(), pszFIDColumnName, pszTableName, pszFIDColumnName );
425 : }
426 :
427 3 : if (bCreateTable)
428 3 : Log(osCommand);
429 :
430 : /* -------------------------------------------------------------------- */
431 : /* Eventually we should be adding this table to a table of */
432 : /* "geometric layers", capturing the WKT projection, and */
433 : /* perhaps some other housekeeping. */
434 : /* -------------------------------------------------------------------- */
435 3 : if( bCreateTable && bHavePostGIS && !EQUAL(pszGeomType, "geography"))
436 : {
437 : osCommand.Printf(
438 : "SELECT AddGeometryColumn('%s',%s,'%s',%d,'%s',%d)",
439 : pszSchemaName, pszEscapedTableNameSingleQuote, pszGFldName,
440 2 : nSRSId, pszGeometryType, nDimension );
441 2 : Log(osCommand);
442 : }
443 :
444 3 : if( bCreateTable && bHavePostGIS )
445 : {
446 : /* -------------------------------------------------------------------- */
447 : /* Create the spatial index. */
448 : /* */
449 : /* We're doing this before we add geometry and record to the table */
450 : /* so this may not be exactly the best way to do it. */
451 : /* -------------------------------------------------------------------- */
452 2 : const char *pszSI = CSLFetchNameValue( papszOptions, "SPATIAL_INDEX" );
453 2 : if( pszSI == NULL || CSLTestBoolean(pszSI) )
454 : {
455 : osCommand.Printf("CREATE INDEX \"%s_geom_idx\" "
456 : "ON \"%s\".\"%s\" "
457 : "USING GIST (\"%s\")",
458 2 : pszTableName, pszSchemaName, pszTableName, pszGFldName);
459 :
460 2 : Log(osCommand);
461 : }
462 : }
463 :
464 : /* -------------------------------------------------------------------- */
465 : /* Create the layer object. */
466 : /* -------------------------------------------------------------------- */
467 : OGRPGDumpLayer *poLayer;
468 :
469 3 : int bWriteAsHex = !CSLFetchBoolean(papszOptions,"WRITE_EWKT_GEOM",FALSE);
470 :
471 : poLayer = new OGRPGDumpLayer( this, pszSchemaName, pszTableName, pszGFldName,
472 3 : pszFIDColumnName, nDimension, nSRSId, bWriteAsHex, bCreateTable );
473 6 : poLayer->SetLaunderFlag( CSLFetchBoolean(papszOptions,"LAUNDER",TRUE) );
474 3 : poLayer->SetPrecisionFlag( CSLFetchBoolean(papszOptions,"PRECISION",TRUE));
475 :
476 : /* -------------------------------------------------------------------- */
477 : /* Add layer to data source layer list. */
478 : /* -------------------------------------------------------------------- */
479 : papoLayers = (OGRPGDumpLayer **)
480 3 : CPLRealloc( papoLayers, sizeof(OGRPGDumpLayer *) * (nLayers+1) );
481 :
482 3 : papoLayers[nLayers++] = poLayer;
483 :
484 3 : CPLFree( pszTableName );
485 3 : CPLFree( pszSchemaName );
486 :
487 3 : return poLayer;
488 : }
489 :
490 : /************************************************************************/
491 : /* TestCapability() */
492 : /************************************************************************/
493 :
494 0 : int OGRPGDumpDataSource::TestCapability( const char * pszCap )
495 :
496 : {
497 0 : if( EQUAL(pszCap,ODsCCreateLayer) )
498 0 : return TRUE;
499 : else
500 0 : return FALSE;
501 : }
502 :
503 : /************************************************************************/
504 : /* GetLayer() */
505 : /************************************************************************/
506 :
507 0 : OGRLayer *OGRPGDumpDataSource::GetLayer( int iLayer )
508 :
509 : {
510 0 : if( iLayer < 0 || iLayer >= nLayers )
511 0 : return NULL;
512 : else
513 0 : return papoLayers[iLayer];
514 : }
515 :
516 : /************************************************************************/
517 : /* Log() */
518 : /************************************************************************/
519 :
520 69 : void OGRPGDumpDataSource::Log(const char* pszStr, int bAddSemiColumn)
521 : {
522 69 : if (fp == NULL)
523 : {
524 3 : if (bTriedOpen)
525 0 : return;
526 3 : bTriedOpen = TRUE;
527 3 : fp = VSIFOpenL(pszName, "wb");
528 3 : if (fp == NULL)
529 : {
530 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot create %s", pszName);
531 0 : return;
532 : }
533 : }
534 :
535 69 : if (bAddSemiColumn)
536 47 : VSIFPrintfL(fp, "%s;%s", pszStr, pszEOL);
537 : else
538 22 : VSIFPrintfL(fp, "%s%s", pszStr, pszEOL);
539 : }
540 :
541 : /************************************************************************/
542 : /* StartCopy() */
543 : /************************************************************************/
544 2 : void OGRPGDumpDataSource::StartCopy( OGRPGDumpLayer *poPGLayer )
545 : {
546 2 : EndCopy();
547 2 : poLayerInCopyMode = poPGLayer;
548 2 : }
549 :
550 : /************************************************************************/
551 : /* EndCopy() */
552 : /************************************************************************/
553 8 : OGRErr OGRPGDumpDataSource::EndCopy( )
554 : {
555 8 : if( poLayerInCopyMode != NULL )
556 : {
557 2 : OGRErr result = poLayerInCopyMode->EndCopy();
558 2 : poLayerInCopyMode = NULL;
559 :
560 2 : return result;
561 : }
562 : else
563 6 : return OGRERR_NONE;
564 : }
|