1 /******************************************************************************
2 * $Id: ogrocitablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $
3 *
4 * Project: Oracle Spatial Driver
5 * Purpose: Implementation of the OGROCITableLayer class. This class provides
6 * layer semantics on a table, but utilizing alot of machinery from
7 * the OGROCILayer base class.
8 * Author: Frank Warmerdam, warmerdam@pobox.com
9 *
10 ******************************************************************************
11 * Copyright (c) 2002, Frank Warmerdam <warmerdam@pobox.com>
12 *
13 * Permission is hereby granted, free of charge, to any person obtaining a
14 * copy of this software and associated documentation files (the "Software"),
15 * to deal in the Software without restriction, including without limitation
16 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 * and/or sell copies of the Software, and to permit persons to whom the
18 * Software is furnished to do so, subject to the following conditions:
19 *
20 * The above copyright notice and this permission notice shall be included
21 * in all copies or substantial portions of the Software.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 * DEALINGS IN THE SOFTWARE.
30 ****************************************************************************/
31
32 #include "ogr_oci.h"
33 #include "cpl_conv.h"
34 #include "cpl_string.h"
35
36 CPL_CVSID("$Id: ogrocitablelayer.cpp 28809 2015-03-28 17:10:07Z rouault $");
37
38 static int nDiscarded = 0;
39 static int nHits = 0;
40
41 #define HSI_UNKNOWN -2
42
43 /************************************************************************/
44 /* OGROCITableLayer() */
45 /************************************************************************/
46
OGROCITableLayer(OGROCIDataSource * poDSIn,const char * pszTableName,OGRwkbGeometryType eGType,int nSRIDIn,int bUpdate,int bNewLayerIn)47 OGROCITableLayer::OGROCITableLayer( OGROCIDataSource *poDSIn,
48 const char * pszTableName, OGRwkbGeometryType eGType,
49 int nSRIDIn, int bUpdate, int bNewLayerIn )
50
51 {
52 poDS = poDSIn;
53 bExtentUpdated = false;
54
55 pszQuery = NULL;
56 pszWHERE = CPLStrdup( "" );
57 pszQueryStatement = NULL;
58
59 bUpdateAccess = bUpdate;
60 bNewLayer = bNewLayerIn;
61
62 iNextShapeId = 0;
63 iNextFIDToWrite = -1;
64
65 bValidTable = FALSE;
66 if( bNewLayerIn )
67 bHaveSpatialIndex = FALSE;
68 else
69 bHaveSpatialIndex = HSI_UNKNOWN;
70
71 poFeatureDefn = ReadTableDefinition( pszTableName );
72 if( eGType != wkbUnknown && poFeatureDefn->GetGeomFieldCount() > 0 )
73 poFeatureDefn->GetGeomFieldDefn(0)->SetType(eGType);
74 SetDescription( poFeatureDefn->GetName() );
75
76 nSRID = nSRIDIn;
77 if( nSRID == -1 )
78 nSRID = LookupTableSRID();
79
80 poSRS = poDSIn->FetchSRS( nSRID );
81 if( poSRS != NULL )
82 poSRS->Reference();
83
84 hOrdVARRAY = NULL;
85 hElemInfoVARRAY = NULL;
86
87 poBoundStatement = NULL;
88
89 nWriteCacheMax = 0;
90 nWriteCacheUsed = 0;
91 pasWriteGeoms = NULL;
92 papsWriteGeomMap = NULL;
93 pasWriteGeomInd = NULL;
94 papsWriteGeomIndMap = NULL;
95
96 papWriteFields = NULL;
97 papaeWriteFieldInd = NULL;
98
99 panWriteFIDs = NULL;
100
101 ResetReading();
102 }
103
104 /************************************************************************/
105 /* ~OGROCITableLayer() */
106 /************************************************************************/
107
~OGROCITableLayer()108 OGROCITableLayer::~OGROCITableLayer()
109
110 {
111 int i;
112
113 SyncToDisk();
114
115 CPLFree( panWriteFIDs );
116 if( papWriteFields != NULL )
117 {
118 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
119 {
120 CPLFree( papWriteFields[i] );
121 CPLFree( papaeWriteFieldInd[i] );
122 }
123 }
124
125 CPLFree( papWriteFields );
126 CPLFree( papaeWriteFieldInd );
127
128 if( poBoundStatement != NULL )
129 delete poBoundStatement;
130
131 CPLFree( pasWriteGeomInd );
132 CPLFree( papsWriteGeomIndMap );
133
134 CPLFree( papsWriteGeomMap );
135 CPLFree( pasWriteGeoms );
136
137
138 CPLFree( pszQuery );
139 CPLFree( pszWHERE );
140
141 if( poSRS != NULL && poSRS->Dereference() == 0 )
142 delete poSRS;
143 }
144
145 /************************************************************************/
146 /* ReadTableDefinition() */
147 /* */
148 /* Build a schema from the named table. Done by querying the */
149 /* catalog. */
150 /************************************************************************/
151
ReadTableDefinition(const char * pszTable)152 OGRFeatureDefn *OGROCITableLayer::ReadTableDefinition( const char * pszTable )
153
154 {
155 OGROCISession *poSession = poDS->GetSession();
156 sword nStatus;
157
158 CPLString osUnquotedTableName;
159 CPLString osQuotedTableName;
160
161 /* -------------------------------------------------------------------- */
162 /* Split out the owner if available. */
163 /* -------------------------------------------------------------------- */
164 if( strstr(pszTable,".") != NULL )
165 {
166 osTableName = strstr(pszTable,".") + 1;
167 osOwner.assign( pszTable, strlen(pszTable)-osTableName.size() - 1 );
168 osUnquotedTableName.Printf( "%s.%s", osOwner.c_str(), osTableName.c_str() );
169 osQuotedTableName.Printf( "\"%s\".\"%s\"", osOwner.c_str(), osTableName.c_str() );
170 }
171 else
172 {
173 osTableName = pszTable;
174 osOwner = "";
175 osUnquotedTableName.Printf( "%s", pszTable );
176 osQuotedTableName.Printf( "\"%s\"", pszTable );
177 }
178
179 OGRFeatureDefn *poDefn = new OGRFeatureDefn( osUnquotedTableName.c_str() );
180
181 poDefn->Reference();
182
183 /* -------------------------------------------------------------------- */
184 /* Do a DescribeAll on the table. */
185 /* -------------------------------------------------------------------- */
186 OCIParam *hAttrParam = NULL;
187 OCIParam *hAttrList = NULL;
188
189 // Table name unquoted
190
191 nStatus =
192 OCIDescribeAny( poSession->hSvcCtx, poSession->hError,
193 (dvoid *) osUnquotedTableName.c_str(),
194 osUnquotedTableName.length(), OCI_OTYPE_NAME,
195 OCI_DEFAULT, OCI_PTYPE_TABLE, poSession->hDescribe );
196
197 if( poSession->Failed( nStatus, "OCIDescribeAny" ) )
198 {
199 CPLErrorReset();
200
201 // View name unquoted
202
203 nStatus =
204 OCIDescribeAny(poSession->hSvcCtx, poSession->hError,
205 (dvoid *) osQuotedTableName.c_str(),
206 osQuotedTableName.length(), OCI_OTYPE_NAME,
207 OCI_DEFAULT, OCI_PTYPE_VIEW, poSession->hDescribe );
208
209 if( poSession->Failed( nStatus, "OCIDescribeAny" ) )
210 {
211 CPLErrorReset();
212
213 // Table name quoted
214
215 nStatus =
216 OCIDescribeAny( poSession->hSvcCtx, poSession->hError,
217 (dvoid *) osQuotedTableName.c_str(),
218 osQuotedTableName.length(), OCI_OTYPE_NAME,
219 OCI_DEFAULT, OCI_PTYPE_TABLE, poSession->hDescribe );
220
221 if( poSession->Failed( nStatus, "OCIDescribeAny" ) )
222 {
223 CPLErrorReset();
224
225 // View name quoted
226
227 nStatus =
228 OCIDescribeAny(poSession->hSvcCtx, poSession->hError,
229 (dvoid *) osQuotedTableName.c_str(),
230 osQuotedTableName.length(), OCI_OTYPE_NAME,
231 OCI_DEFAULT, OCI_PTYPE_VIEW, poSession->hDescribe );
232
233 if( poSession->Failed( nStatus, "OCIDescribeAny" ) )
234 return poDefn;
235 }
236 }
237 }
238
239 if( poSession->Failed(
240 OCIAttrGet( poSession->hDescribe, OCI_HTYPE_DESCRIBE,
241 &hAttrParam, 0, OCI_ATTR_PARAM, poSession->hError ),
242 "OCIAttrGet(ATTR_PARAM)") )
243 return poDefn;
244
245 if( poSession->Failed(
246 OCIAttrGet( hAttrParam, OCI_DTYPE_PARAM, &hAttrList, 0,
247 OCI_ATTR_LIST_COLUMNS, poSession->hError ),
248 "OCIAttrGet(ATTR_LIST_COLUMNS)" ) )
249 return poDefn;
250
251 /* -------------------------------------------------------------------- */
252 /* What is the name of the column to use as FID? This defaults */
253 /* to OGR_FID but we allow it to be overridden by a config */
254 /* variable. Ideally we would identify a column that is a */
255 /* primary key and use that, but I'm not yet sure how to */
256 /* accomplish that. */
257 /* -------------------------------------------------------------------- */
258 const char *pszExpectedFIDName =
259 CPLGetConfigOption( "OCI_FID", "OGR_FID" );
260 int bGeomFieldNullable = FALSE;
261
262 /* -------------------------------------------------------------------- */
263 /* Parse the returned table information. */
264 /* -------------------------------------------------------------------- */
265 for( int iRawFld = 0; TRUE; iRawFld++ )
266 {
267 OGRFieldDefn oField( "", OFTString);
268 OCIParam *hParmDesc;
269 ub2 nOCIType;
270 ub4 nOCILen;
271 sword nStatus;
272
273 nStatus = OCIParamGet( hAttrList, OCI_DTYPE_PARAM,
274 poSession->hError, (dvoid**)&hParmDesc,
275 (ub4) iRawFld+1 );
276 if( nStatus != OCI_SUCCESS )
277 break;
278
279 if( poSession->GetParmInfo( hParmDesc, &oField, &nOCIType, &nOCILen )
280 != CE_None )
281 return poDefn;
282
283 if( oField.GetType() == OFTBinary )
284 {
285 if( nOCIType == 108 && pszGeomName == NULL )
286 {
287 CPLFree( pszGeomName );
288 pszGeomName = CPLStrdup( oField.GetNameRef() );
289 iGeomColumn = iRawFld;
290 bGeomFieldNullable = oField.IsNullable();
291 }
292 continue;
293 }
294
295 if( EQUAL(oField.GetNameRef(),pszExpectedFIDName)
296 && (oField.GetType() == OFTInteger ||
297 oField.GetType() == OFTInteger64) )
298 {
299 pszFIDName = CPLStrdup(oField.GetNameRef());
300 continue;
301 }
302
303 poDefn->AddFieldDefn( &oField );
304 }
305
306 CPLString osSQL;
307 osSQL.Printf("SELECT COLUMN_NAME, DATA_DEFAULT FROM user_tab_columns WHERE DATA_DEFAULT IS NOT NULL AND TABLE_NAME = '%s'",
308 CPLString(pszTable).toupper().c_str());
309 OGRLayer* poSQLLyr = poDS->ExecuteSQL(osSQL, NULL, NULL);
310 if( poSQLLyr != NULL )
311 {
312 OGRFeature* poFeature;
313 while( (poFeature = poSQLLyr->GetNextFeature()) != NULL )
314 {
315 const char* pszColName = poFeature->GetFieldAsString(0);
316 const char* pszDefault = poFeature->GetFieldAsString(1);
317 int nIdx = poDefn->GetFieldIndex(pszColName);
318 if( nIdx >= 0 )
319 poDefn->GetFieldDefn(nIdx)->SetDefault(pszDefault);
320 delete poFeature;
321 }
322 poDS->ReleaseResultSet(poSQLLyr);
323 }
324
325 if( EQUAL(pszExpectedFIDName, "OGR_FID") && pszFIDName )
326 {
327 for(int i=0;i<poDefn->GetFieldCount();i++)
328 {
329 // This is presumably a Integer since we always create Integer64 with a
330 // defined precision
331 if( poDefn->GetFieldDefn(i)->GetType() == OFTInteger64 &&
332 poDefn->GetFieldDefn(i)->GetWidth() == 0 )
333 {
334 poDefn->GetFieldDefn(i)->SetType(OFTInteger);
335 }
336 }
337 }
338
339 /* -------------------------------------------------------------------- */
340 /* Identify Geometry dimension */
341 /* -------------------------------------------------------------------- */
342
343 if( pszGeomName != NULL && strlen(pszGeomName) > 0 )
344 {
345 OGROCIStringBuf oDimCmd;
346 OGROCIStatement oDimStatement( poSession );
347 char **papszResult;
348 int iDim = -1;
349
350 oDimCmd.Append( "SELECT COUNT(*) FROM ALL_SDO_GEOM_METADATA u," );
351 oDimCmd.Append( " TABLE(u.diminfo) t" );
352 oDimCmd.Append( " WHERE u.table_name = '" );
353 oDimCmd.Append( osTableName );
354 oDimCmd.Append( "' AND u.column_name = '" );
355 oDimCmd.Append( pszGeomName );
356 oDimCmd.Append( "'" );
357
358 oDimStatement.Execute( oDimCmd.GetString() );
359
360 papszResult = oDimStatement.SimpleFetchRow();
361
362 if( CSLCount(papszResult) < 1 )
363 {
364 OGROCIStringBuf oDimCmd2;
365 OGROCIStatement oDimStatement2( poSession );
366 char **papszResult2;
367
368 CPLErrorReset();
369
370 oDimCmd2.Appendf( 1024,
371 "select m.sdo_index_dims\n"
372 "from all_sdo_index_metadata m, all_sdo_index_info i\n"
373 "where i.index_name = m.sdo_index_name\n"
374 " and i.sdo_index_owner = m.sdo_index_owner\n"
375 " and i.table_name = upper('%s')",
376 osTableName.c_str() );
377
378 oDimStatement2.Execute( oDimCmd2.GetString() );
379
380 papszResult2 = oDimStatement2.SimpleFetchRow();
381
382 if( CSLCount( papszResult2 ) > 0 )
383 {
384 iDim = atoi( papszResult2[0] );
385 }
386 else
387 {
388 // we want to clear any errors to avoid confusing the application.
389 CPLErrorReset();
390 }
391 }
392 else
393 {
394 iDim = atoi( papszResult[0] );
395 }
396
397 if( iDim > 0 )
398 {
399 SetDimension( iDim );
400 }
401 else
402 {
403 CPLDebug( "OCI", "get dim based of existing data or index failed." );
404 }
405
406 {
407 OGROCIStringBuf oDimCmd2;
408 OGROCIStatement oDimStatement2( poSession );
409 char **papszResult2;
410
411 CPLErrorReset();
412 oDimCmd2.Appendf( 1024,
413 "select m.SDO_LAYER_GTYPE "
414 "from all_sdo_index_metadata m, all_sdo_index_info i "
415 "where i.index_name = m.sdo_index_name "
416 "and i.sdo_index_owner = m.sdo_index_owner "
417 "and i.table_name = upper('%s')",
418 osTableName.c_str() );
419
420 oDimStatement2.Execute( oDimCmd2.GetString() );
421
422 papszResult2 = oDimStatement2.SimpleFetchRow();
423
424 if( CSLCount( papszResult2 ) > 0 )
425 {
426 const char* pszLayerGType = papszResult2[0];
427 OGRwkbGeometryType eGeomType = wkbUnknown;
428 if( EQUAL(pszLayerGType, "POINT") )
429 eGeomType = wkbPoint;
430 else if( EQUAL(pszLayerGType, "LINE") )
431 eGeomType = wkbLineString;
432 else if( EQUAL(pszLayerGType, "POLYGON") )
433 eGeomType = wkbPolygon;
434 else if( EQUAL(pszLayerGType, "MULTIPOINT") )
435 eGeomType = wkbMultiPoint;
436 else if( EQUAL(pszLayerGType, "MULTILINE") )
437 eGeomType = wkbMultiLineString;
438 else if( EQUAL(pszLayerGType, "MULTIPOLYGON") )
439 eGeomType = wkbMultiPolygon;
440 else if( !EQUAL(pszLayerGType, "COLLECTION") )
441 CPLDebug("OCI", "LAYER_GTYPE = %s", pszLayerGType );
442 if( iDim == 3 )
443 eGeomType = wkbSetZ(eGeomType);
444 poDefn->GetGeomFieldDefn(0)->SetType( eGeomType );
445 poDefn->GetGeomFieldDefn(0)->SetNullable( bGeomFieldNullable );
446 }
447 else
448 {
449 // we want to clear any errors to avoid confusing the application.
450 CPLErrorReset();
451 }
452 }
453 }
454 else
455 {
456 poDefn->SetGeomType(wkbNone);
457 }
458
459 bValidTable = TRUE;
460
461 return poDefn;
462 }
463
464 /************************************************************************/
465 /* SetSpatialFilter() */
466 /************************************************************************/
467
SetSpatialFilter(OGRGeometry * poGeomIn)468 void OGROCITableLayer::SetSpatialFilter( OGRGeometry * poGeomIn )
469
470 {
471 if( !InstallFilter( poGeomIn ) )
472 return;
473
474 BuildWhere();
475
476 ResetReading();
477 }
478
479 /************************************************************************/
480 /* TestForSpatialIndex() */
481 /************************************************************************/
482
TestForSpatialIndex(const char * pszSpatWHERE)483 void OGROCITableLayer::TestForSpatialIndex( const char *pszSpatWHERE )
484
485 {
486 OGROCIStringBuf oTestCmd;
487 OGROCIStatement oTestStatement( poDS->GetSession() );
488
489 oTestCmd.Append( "SELECT COUNT(*) FROM " );
490 oTestCmd.Append( poFeatureDefn->GetName() );
491 oTestCmd.Append( pszSpatWHERE );
492
493 if( oTestStatement.Execute( oTestCmd.GetString() ) != CE_None )
494 bHaveSpatialIndex = FALSE;
495 else
496 bHaveSpatialIndex = TRUE;
497 }
498
499 /************************************************************************/
500 /* BuildWhere() */
501 /* */
502 /* Build the WHERE statement appropriate to the current set of */
503 /* criteria (spatial and attribute queries). */
504 /************************************************************************/
505
BuildWhere()506 void OGROCITableLayer::BuildWhere()
507
508 {
509 OGROCIStringBuf oWHERE;
510
511 CPLFree( pszWHERE );
512 pszWHERE = NULL;
513
514 if( m_poFilterGeom != NULL && bHaveSpatialIndex )
515 {
516 OGREnvelope sEnvelope;
517
518 m_poFilterGeom->getEnvelope( &sEnvelope );
519
520 oWHERE.Append( " WHERE sdo_filter(" );
521 oWHERE.Append( pszGeomName );
522 oWHERE.Append( ", MDSYS.SDO_GEOMETRY(2003," );
523 if( nSRID == -1 )
524 oWHERE.Append( "NULL" );
525 else
526 oWHERE.Appendf( 15, "%d", nSRID );
527 oWHERE.Append( ",NULL," );
528 oWHERE.Append( "MDSYS.SDO_ELEM_INFO_ARRAY(1,1003,1)," );
529 oWHERE.Append( "MDSYS.SDO_ORDINATE_ARRAY(" );
530 oWHERE.Appendf( 600,
531 "%.16g,%.16g,%.16g,%.16g,%.16g,%.16g,%.16g,%.16g,%.16g,%.16g",
532 sEnvelope.MinX, sEnvelope.MinY,
533 sEnvelope.MaxX, sEnvelope.MinY,
534 sEnvelope.MaxX, sEnvelope.MaxY,
535 sEnvelope.MinX, sEnvelope.MaxY,
536 sEnvelope.MinX, sEnvelope.MinY);
537 oWHERE.Append( ")), 'querytype=window') = 'TRUE' " );
538 }
539
540 if( bHaveSpatialIndex == HSI_UNKNOWN )
541 {
542 TestForSpatialIndex( oWHERE.GetString() );
543 if( !bHaveSpatialIndex )
544 oWHERE.Clear();
545 }
546
547 if( pszQuery != NULL )
548 {
549 if( oWHERE.GetLast() == '\0' )
550 oWHERE.Append( "WHERE " );
551 else
552 oWHERE.Append( "AND " );
553
554 oWHERE.Append( pszQuery );
555 }
556
557 pszWHERE = oWHERE.StealString();
558 }
559
560 /************************************************************************/
561 /* BuildFullQueryStatement() */
562 /************************************************************************/
563
BuildFullQueryStatement()564 void OGROCITableLayer::BuildFullQueryStatement()
565
566 {
567 if( pszQueryStatement != NULL )
568 {
569 CPLFree( pszQueryStatement );
570 pszQueryStatement = NULL;
571 }
572
573 OGROCIStringBuf oCmd;
574 char *pszFields = BuildFields();
575
576 oCmd.Append( "SELECT " );
577 oCmd.Append( pszFields );
578 oCmd.Append( " FROM " );
579 oCmd.Append( poFeatureDefn->GetName() );
580 oCmd.Append( " " );
581 oCmd.Append( pszWHERE );
582
583 pszQueryStatement = oCmd.StealString();
584
585 CPLFree( pszFields );
586 }
587
588 /************************************************************************/
589 /* GetFeature() */
590 /************************************************************************/
591
GetFeature(GIntBig nFeatureId)592 OGRFeature *OGROCITableLayer::GetFeature( GIntBig nFeatureId )
593
594 {
595
596 /* -------------------------------------------------------------------- */
597 /* If we don't have an FID column scan for the desired feature. */
598 /* -------------------------------------------------------------------- */
599 if( pszFIDName == NULL )
600 return OGROCILayer::GetFeature( nFeatureId );
601
602 /* -------------------------------------------------------------------- */
603 /* Clear any existing query. */
604 /* -------------------------------------------------------------------- */
605 ResetReading();
606
607 /* -------------------------------------------------------------------- */
608 /* Build query for this specific feature. */
609 /* -------------------------------------------------------------------- */
610 OGROCIStringBuf oCmd;
611 char *pszFields = BuildFields();
612
613 oCmd.Append( "SELECT " );
614 oCmd.Append( pszFields );
615 oCmd.Append( " FROM " );
616 oCmd.Append( poFeatureDefn->GetName() );
617 oCmd.Append( " " );
618 oCmd.Appendf( 50+strlen(pszFIDName),
619 " WHERE \"%s\" = " CPL_FRMT_GIB " ",
620 pszFIDName, nFeatureId );
621
622 /* -------------------------------------------------------------------- */
623 /* Execute the statement. */
624 /* -------------------------------------------------------------------- */
625 if( !ExecuteQuery( oCmd.GetString() ) )
626 return NULL;
627
628 /* -------------------------------------------------------------------- */
629 /* Get the feature. */
630 /* -------------------------------------------------------------------- */
631 OGRFeature *poFeature;
632
633 poFeature = GetNextRawFeature();
634
635 if( poFeature != NULL && poFeature->GetGeometryRef() != NULL )
636 poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
637
638 /* -------------------------------------------------------------------- */
639 /* Cleanup the statement. */
640 /* -------------------------------------------------------------------- */
641 ResetReading();
642
643 /* -------------------------------------------------------------------- */
644 /* verify the FID. */
645 /* -------------------------------------------------------------------- */
646 if( poFeature != NULL && poFeature->GetFID() != nFeatureId )
647 {
648 CPLError( CE_Failure, CPLE_AppDefined,
649 "OGROCITableLayer::GetFeature(" CPL_FRMT_GIB ") ... query returned feature " CPL_FRMT_GIB " instead!",
650 nFeatureId, poFeature->GetFID() );
651 delete poFeature;
652 return NULL;
653 }
654 else
655 return poFeature;
656 }
657
658 /************************************************************************/
659 /* GetNextFeature() */
660 /* */
661 /* We override the next feature method because we know that we */
662 /* implement the attribute query within the statement and so we */
663 /* don't have to test here. Eventually the spatial query will */
664 /* be fully tested within the statement as well. */
665 /************************************************************************/
666
GetNextFeature()667 OGRFeature *OGROCITableLayer::GetNextFeature()
668
669 {
670
671 for( ; TRUE; )
672 {
673 OGRFeature *poFeature;
674
675 poFeature = GetNextRawFeature();
676 if( poFeature == NULL )
677 {
678 CPLDebug( "OCI", "Query complete, got %d hits, and %d discards.",
679 nHits, nDiscarded );
680 nHits = 0;
681 nDiscarded = 0;
682 return NULL;
683 }
684
685 if( m_poFilterGeom == NULL
686 || FilterGeometry( poFeature->GetGeometryRef() ) )
687 {
688 nHits++;
689 if( poFeature->GetGeometryRef() != NULL )
690 poFeature->GetGeometryRef()->assignSpatialReference( poSRS );
691 return poFeature;
692 }
693
694 if( m_poFilterGeom != NULL )
695 nDiscarded++;
696
697 delete poFeature;
698 }
699 }
700
701 /************************************************************************/
702 /* ResetReading() */
703 /************************************************************************/
704
ResetReading()705 void OGROCITableLayer::ResetReading()
706
707 {
708 nHits = 0;
709 nDiscarded = 0;
710
711 FlushPendingFeatures();
712
713 BuildFullQueryStatement();
714
715 OGROCILayer::ResetReading();
716 }
717
718 /************************************************************************/
719 /* BuildFields() */
720 /* */
721 /* Build list of fields to fetch, performing any required */
722 /* transformations (such as on geometry). */
723 /************************************************************************/
724
BuildFields()725 char *OGROCITableLayer::BuildFields()
726
727 {
728 int i;
729 OGROCIStringBuf oFldList;
730
731 if( pszGeomName )
732 {
733 oFldList.Append( "\"" );
734 oFldList.Append( pszGeomName );
735 oFldList.Append( "\"" );
736 iGeomColumn = 0;
737 }
738
739 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
740 {
741 const char *pszName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
742
743 if( oFldList.GetLast() != '\0' )
744 oFldList.Append( "," );
745
746 oFldList.Append( "\"" );
747 oFldList.Append( pszName );
748 oFldList.Append( "\"" );
749 }
750
751 if( pszFIDName != NULL )
752 {
753 iFIDColumn = poFeatureDefn->GetFieldCount();
754 oFldList.Append( ",\"" );
755 oFldList.Append( pszFIDName );
756 oFldList.Append( "\"" );
757 }
758
759 return oFldList.StealString();
760 }
761
762 /************************************************************************/
763 /* SetAttributeFilter() */
764 /************************************************************************/
765
SetAttributeFilter(const char * pszQuery)766 OGRErr OGROCITableLayer::SetAttributeFilter( const char *pszQuery )
767
768 {
769 CPLFree(m_pszAttrQueryString);
770 m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : NULL;
771
772 if( (pszQuery == NULL && this->pszQuery == NULL)
773 || (pszQuery != NULL && this->pszQuery != NULL
774 && strcmp(pszQuery,this->pszQuery) == 0) )
775 return OGRERR_NONE;
776
777 CPLFree( this->pszQuery );
778
779 if( pszQuery == NULL )
780 this->pszQuery = NULL;
781 else
782 this->pszQuery = CPLStrdup( pszQuery );
783
784 BuildWhere();
785
786 ResetReading();
787
788 return OGRERR_NONE;
789 }
790
791 /************************************************************************/
792 /* ISetFeature() */
793 /* */
794 /* We implement SetFeature() by deleting the existing row (if */
795 /* it exists), and then using CreateFeature() to write it out */
796 /* tot he table normally. CreateFeature() will preserve the */
797 /* existing FID if possible. */
798 /************************************************************************/
799
ISetFeature(OGRFeature * poFeature)800 OGRErr OGROCITableLayer::ISetFeature( OGRFeature *poFeature )
801
802 {
803 /* -------------------------------------------------------------------- */
804 /* Do some validation. */
805 /* -------------------------------------------------------------------- */
806 if( pszFIDName == NULL )
807 {
808 CPLError( CE_Failure, CPLE_AppDefined,
809 "OGROCITableLayer::ISetFeature(" CPL_FRMT_GIB ") failed because there is "
810 "no apparent FID column on table %s.",
811 poFeature->GetFID(),
812 poFeatureDefn->GetName() );
813
814 return OGRERR_FAILURE;
815 }
816
817 if( poFeature->GetFID() == OGRNullFID )
818 {
819 CPLError( CE_Failure, CPLE_AppDefined,
820 "OGROCITableLayer::ISetFeature(" CPL_FRMT_GIB ") failed because the feature "
821 "has no FID!", poFeature->GetFID() );
822
823 return OGRERR_FAILURE;
824 }
825
826 OGRErr eErr = DeleteFeature(poFeature->GetFID());
827 if( eErr != OGRERR_NONE )
828 return eErr;
829
830 return CreateFeature( poFeature );
831 }
832
833 /************************************************************************/
834 /* DeleteFeature() */
835 /************************************************************************/
836
DeleteFeature(GIntBig nFID)837 OGRErr OGROCITableLayer::DeleteFeature( GIntBig nFID )
838
839 {
840 /* -------------------------------------------------------------------- */
841 /* Do some validation. */
842 /* -------------------------------------------------------------------- */
843 if( pszFIDName == NULL )
844 {
845 CPLError( CE_Failure, CPLE_AppDefined,
846 "OGROCITableLayer::DeleteFeature(" CPL_FRMT_GIB ") failed because there is "
847 "no apparent FID column on table %s.",
848 nFID,
849 poFeatureDefn->GetName() );
850
851 return OGRERR_FAILURE;
852 }
853
854 if( nFID == OGRNullFID )
855 {
856 CPLError( CE_Failure, CPLE_AppDefined,
857 "OGROCITableLayer::DeleteFeature(" CPL_FRMT_GIB ") failed for Null FID",
858 nFID );
859
860 return OGRERR_FAILURE;
861 }
862
863 /* -------------------------------------------------------------------- */
864 /* Prepare the delete command, and execute. We don't check the */
865 /* error result of the execute, since attempting to Set a */
866 /* non-existing feature may be OK. */
867 /* -------------------------------------------------------------------- */
868 OGROCIStringBuf oCmdText;
869 OGROCIStatement oCmdStatement( poDS->GetSession() );
870
871 oCmdText.Appendf( strlen(poFeatureDefn->GetName())+strlen(pszFIDName)+100,
872 "DELETE FROM %s WHERE \"%s\" = " CPL_FRMT_GIB,
873 poFeatureDefn->GetName(),
874 pszFIDName,
875 nFID );
876
877 if( oCmdStatement.Execute( oCmdText.GetString() ) == CE_None )
878 return (oCmdStatement.GetAffectedRows() > 0) ? OGRERR_NONE : OGRERR_NON_EXISTING_FEATURE;
879 else
880 return OGRERR_FAILURE;
881 }
882
883 /************************************************************************/
884 /* ICreateFeature() */
885 /************************************************************************/
886
ICreateFeature(OGRFeature * poFeature)887 OGRErr OGROCITableLayer::ICreateFeature( OGRFeature *poFeature )
888
889 {
890 /* -------------------------------------------------------------------- */
891 /* Add extents of this geometry to the existing layer extents. */
892 /* -------------------------------------------------------------------- */
893 if( poFeature->GetGeometryRef() != NULL )
894 {
895 OGREnvelope sThisExtent;
896
897 poFeature->GetGeometryRef()->getEnvelope( &sThisExtent );
898
899 if( !sExtent.Contains( sThisExtent ) )
900 {
901 sExtent.Merge( sThisExtent );
902 bExtentUpdated = true;
903 }
904 }
905
906 /* -------------------------------------------------------------------- */
907 /* Do the actual creation. */
908 /* -------------------------------------------------------------------- */
909 if( CSLFetchBoolean( papszOptions, "MULTI_LOAD", true ) )
910 return BoundCreateFeature( poFeature );
911 else
912 return UnboundCreateFeature( poFeature );
913 }
914
915 /************************************************************************/
916 /* UnboundCreateFeature() */
917 /************************************************************************/
918
UnboundCreateFeature(OGRFeature * poFeature)919 OGRErr OGROCITableLayer::UnboundCreateFeature( OGRFeature *poFeature )
920
921 {
922 OGROCISession *poSession = poDS->GetSession();
923 char *pszCommand;
924 int i, bNeedComma = FALSE;
925 unsigned int nCommandBufSize;;
926
927 /* -------------------------------------------------------------------- */
928 /* Prepare SQL statement buffer. */
929 /* -------------------------------------------------------------------- */
930 nCommandBufSize = 2000;
931 pszCommand = (char *) CPLMalloc(nCommandBufSize);
932
933 /* -------------------------------------------------------------------- */
934 /* Form the INSERT command. */
935 /* -------------------------------------------------------------------- */
936 sprintf( pszCommand, "INSERT INTO \"%s\"(\"", poFeatureDefn->GetName() );
937
938 if( poFeature->GetGeometryRef() != NULL )
939 {
940 bNeedComma = TRUE;
941 strcat( pszCommand, pszGeomName );
942 }
943
944 if( pszFIDName != NULL )
945 {
946 if( bNeedComma )
947 strcat( pszCommand, "\",\"" );
948
949 strcat( pszCommand, pszFIDName );
950 bNeedComma = TRUE;
951 }
952
953
954 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
955 {
956 if( !poFeature->IsFieldSet( i ) )
957 continue;
958
959 if( !bNeedComma )
960 bNeedComma = TRUE;
961 else
962 strcat( pszCommand, "\",\"" );
963
964 sprintf( pszCommand + strlen(pszCommand), "%s",
965 poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
966 }
967
968 strcat( pszCommand, "\") VALUES (" );
969
970 CPLAssert( strlen(pszCommand) < nCommandBufSize );
971
972 /* -------------------------------------------------------------------- */
973 /* Set the geometry */
974 /* -------------------------------------------------------------------- */
975 bNeedComma = poFeature->GetGeometryRef() != NULL;
976 if( poFeature->GetGeometryRef() != NULL)
977 {
978 OGRGeometry *poGeometry = poFeature->GetGeometryRef();
979 char szSDO_GEOMETRY[512];
980 char szSRID[128];
981
982 if( nSRID == -1 )
983 strcpy( szSRID, "NULL" );
984 else
985 sprintf( szSRID, "%d", nSRID );
986
987 if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
988 {
989 OGRPoint *poPoint = (OGRPoint *) poGeometry;
990
991 if( nDimension == 2 )
992 CPLsprintf( szSDO_GEOMETRY,
993 "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,0),NULL,NULL)",
994 SDO_GEOMETRY, 2001, szSRID,
995 poPoint->getX(), poPoint->getY() );
996 else
997 CPLsprintf( szSDO_GEOMETRY,
998 "%s(%d,%s,MDSYS.SDO_POINT_TYPE(%.16g,%.16g,%.16g),NULL,NULL)",
999 SDO_GEOMETRY, 3001, szSRID,
1000 poPoint->getX(), poPoint->getY(), poPoint->getZ() );
1001 }
1002 else
1003 {
1004 int nGType;
1005
1006 if( TranslateToSDOGeometry( poFeature->GetGeometryRef(), &nGType )
1007 == OGRERR_NONE )
1008 sprintf( szSDO_GEOMETRY,
1009 "%s(%d,%s,NULL,:elem_info,:ordinates)",
1010 SDO_GEOMETRY, nGType, szSRID );
1011 else
1012 sprintf( szSDO_GEOMETRY, "NULL" );
1013 }
1014
1015 if( strlen(pszCommand) + strlen(szSDO_GEOMETRY)
1016 > nCommandBufSize - 50 )
1017 {
1018 nCommandBufSize =
1019 strlen(pszCommand) + strlen(szSDO_GEOMETRY) + 10000;
1020 pszCommand = (char *) CPLRealloc(pszCommand, nCommandBufSize );
1021 }
1022
1023 strcat( pszCommand, szSDO_GEOMETRY );
1024 }
1025
1026 /* -------------------------------------------------------------------- */
1027 /* Set the FID. */
1028 /* -------------------------------------------------------------------- */
1029 int nOffset = strlen(pszCommand);
1030
1031 if( pszFIDName != NULL )
1032 {
1033 GIntBig nFID;
1034
1035 if( bNeedComma )
1036 strcat( pszCommand+nOffset, ", " );
1037 bNeedComma = TRUE;
1038
1039 nOffset += strlen(pszCommand+nOffset);
1040
1041 nFID = poFeature->GetFID();
1042 if( nFID == OGRNullFID )
1043 {
1044 if( iNextFIDToWrite < 0 )
1045 {
1046 iNextFIDToWrite = GetMaxFID() + 1;
1047 }
1048 nFID = iNextFIDToWrite++;
1049 poFeature->SetFID( nFID );
1050 }
1051 sprintf( pszCommand+nOffset, CPL_FRMT_GIB, nFID );
1052 }
1053
1054 /* -------------------------------------------------------------------- */
1055 /* Set the other fields. */
1056 /* -------------------------------------------------------------------- */
1057 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1058 {
1059 if( !poFeature->IsFieldSet( i ) )
1060 continue;
1061
1062 OGRFieldDefn *poFldDefn = poFeatureDefn->GetFieldDefn(i);
1063 const char *pszStrValue = poFeature->GetFieldAsString(i);
1064
1065 if( bNeedComma )
1066 strcat( pszCommand+nOffset, ", " );
1067 else
1068 bNeedComma = TRUE;
1069
1070 if( strlen(pszStrValue) + strlen(pszCommand+nOffset) + nOffset
1071 > nCommandBufSize-50 )
1072 {
1073 nCommandBufSize = strlen(pszCommand) + strlen(pszStrValue) + 10000;
1074 pszCommand = (char *) CPLRealloc(pszCommand, nCommandBufSize );
1075 }
1076
1077 if( poFldDefn->GetType() == OFTInteger
1078 || poFldDefn->GetType() == OFTInteger64
1079 || poFldDefn->GetType() == OFTReal )
1080 {
1081 if( poFldDefn->GetWidth() > 0 && bPreservePrecision
1082 && (int) strlen(pszStrValue) > poFldDefn->GetWidth() )
1083 {
1084 strcat( pszCommand+nOffset, "NULL" );
1085 ReportTruncation( poFldDefn );
1086 }
1087 else
1088 strcat( pszCommand+nOffset, pszStrValue );
1089 }
1090 else
1091 {
1092 int iChar;
1093
1094 /* We need to quote and escape string fields. */
1095 strcat( pszCommand+nOffset, "'" );
1096
1097 nOffset += strlen(pszCommand+nOffset);
1098
1099 for( iChar = 0; pszStrValue[iChar] != '\0'; iChar++ )
1100 {
1101 if( poFldDefn->GetWidth() != 0 && bPreservePrecision
1102 && iChar >= poFldDefn->GetWidth() )
1103 {
1104 ReportTruncation( poFldDefn );
1105 break;
1106 }
1107
1108 if( pszStrValue[iChar] == '\'' )
1109 {
1110 pszCommand[nOffset++] = '\'';
1111 pszCommand[nOffset++] = pszStrValue[iChar];
1112 }
1113 else
1114 pszCommand[nOffset++] = pszStrValue[iChar];
1115 }
1116 pszCommand[nOffset] = '\0';
1117
1118 strcat( pszCommand+nOffset, "'" );
1119 }
1120 nOffset += strlen(pszCommand+nOffset);
1121 }
1122
1123 strcat( pszCommand+nOffset, ")" );
1124
1125 /* -------------------------------------------------------------------- */
1126 /* Prepare statement. */
1127 /* -------------------------------------------------------------------- */
1128 OGROCIStatement oInsert( poSession );
1129 int bHaveOrdinates = strstr(pszCommand,":ordinates") != NULL;
1130 int bHaveElemInfo = strstr(pszCommand,":elem_info") != NULL;
1131
1132 if( oInsert.Prepare( pszCommand ) != CE_None )
1133 {
1134 CPLFree( pszCommand );
1135 return OGRERR_FAILURE;
1136 }
1137
1138 CPLFree( pszCommand );
1139
1140 /* -------------------------------------------------------------------- */
1141 /* Bind and translate the elem_info if we have some. */
1142 /* -------------------------------------------------------------------- */
1143 if( bHaveElemInfo )
1144 {
1145 OCIBind *hBindOrd = NULL;
1146 int i;
1147 OCINumber oci_number;
1148
1149 // Create or clear VARRAY
1150 if( hElemInfoVARRAY == NULL )
1151 {
1152 if( poSession->Failed(
1153 OCIObjectNew( poSession->hEnv, poSession->hError,
1154 poSession->hSvcCtx, OCI_TYPECODE_VARRAY,
1155 poSession->hElemInfoTDO, (dvoid *)NULL,
1156 OCI_DURATION_SESSION,
1157 FALSE, (dvoid **)&hElemInfoVARRAY),
1158 "OCIObjectNew(hElemInfoVARRAY)") )
1159 return OGRERR_FAILURE;
1160 }
1161 else
1162 {
1163 sb4 nOldCount;
1164
1165 OCICollSize( poSession->hEnv, poSession->hError,
1166 hElemInfoVARRAY, &nOldCount );
1167 OCICollTrim( poSession->hEnv, poSession->hError,
1168 nOldCount, hElemInfoVARRAY );
1169 }
1170
1171 // Prepare the VARRAY of ordinate values.
1172 for (i = 0; i < nElemInfoCount; i++)
1173 {
1174 if( poSession->Failed(
1175 OCINumberFromInt( poSession->hError,
1176 (dvoid *) (panElemInfo + i),
1177 (uword)sizeof(int),
1178 OCI_NUMBER_SIGNED,
1179 &oci_number),
1180 "OCINumberFromInt") )
1181 return OGRERR_FAILURE;
1182
1183 if( poSession->Failed(
1184 OCICollAppend( poSession->hEnv, poSession->hError,
1185 (dvoid *) &oci_number,
1186 (dvoid *)0, hElemInfoVARRAY),
1187 "OCICollAppend") )
1188 return OGRERR_FAILURE;
1189 }
1190
1191 // Do the binding.
1192 if( poSession->Failed(
1193 OCIBindByName( oInsert.GetStatement(), &hBindOrd,
1194 poSession->hError,
1195 (text *) ":elem_info", (sb4) -1, (dvoid *) 0,
1196 (sb4) 0, SQLT_NTY, (dvoid *)0, (ub2 *)0,
1197 (ub2 *)0, (ub4)0, (ub4 *)0,
1198 (ub4)OCI_DEFAULT),
1199 "OCIBindByName(:elem_info)") )
1200 return OGRERR_FAILURE;
1201
1202 if( poSession->Failed(
1203 OCIBindObject( hBindOrd, poSession->hError,
1204 poSession->hElemInfoTDO,
1205 (dvoid **)&hElemInfoVARRAY, (ub4 *)0,
1206 (dvoid **)0, (ub4 *)0),
1207 "OCIBindObject(:elem_info)" ) )
1208 return OGRERR_FAILURE;
1209 }
1210
1211 /* -------------------------------------------------------------------- */
1212 /* Bind and translate the ordinates if we have some. */
1213 /* -------------------------------------------------------------------- */
1214 if( bHaveOrdinates )
1215 {
1216 OCIBind *hBindOrd = NULL;
1217 int i;
1218 OCINumber oci_number;
1219
1220 // Create or clear VARRAY
1221 if( hOrdVARRAY == NULL )
1222 {
1223 if( poSession->Failed(
1224 OCIObjectNew( poSession->hEnv, poSession->hError,
1225 poSession->hSvcCtx, OCI_TYPECODE_VARRAY,
1226 poSession->hOrdinatesTDO, (dvoid *)NULL,
1227 OCI_DURATION_SESSION,
1228 FALSE, (dvoid **)&hOrdVARRAY),
1229 "OCIObjectNew(hOrdVARRAY)") )
1230 return OGRERR_FAILURE;
1231 }
1232 else
1233 {
1234 sb4 nOldCount;
1235
1236 OCICollSize( poSession->hEnv, poSession->hError,
1237 hOrdVARRAY, &nOldCount );
1238 OCICollTrim( poSession->hEnv, poSession->hError,
1239 nOldCount, hOrdVARRAY );
1240 }
1241
1242 // Prepare the VARRAY of ordinate values.
1243 for (i = 0; i < nOrdinalCount; i++)
1244 {
1245 if( poSession->Failed(
1246 OCINumberFromReal( poSession->hError,
1247 (dvoid *) (padfOrdinals + i),
1248 (uword)sizeof(double),
1249 &oci_number),
1250 "OCINumberFromReal") )
1251 return OGRERR_FAILURE;
1252
1253 if( poSession->Failed(
1254 OCICollAppend( poSession->hEnv, poSession->hError,
1255 (dvoid *) &oci_number,
1256 (dvoid *)0, hOrdVARRAY),
1257 "OCICollAppend") )
1258 return OGRERR_FAILURE;
1259 }
1260
1261 // Do the binding.
1262 if( poSession->Failed(
1263 OCIBindByName( oInsert.GetStatement(), &hBindOrd,
1264 poSession->hError,
1265 (text *) ":ordinates", (sb4) -1, (dvoid *) 0,
1266 (sb4) 0, SQLT_NTY, (dvoid *)0, (ub2 *)0,
1267 (ub2 *)0, (ub4)0, (ub4 *)0,
1268 (ub4)OCI_DEFAULT),
1269 "OCIBindByName(:ordinates)") )
1270 return OGRERR_FAILURE;
1271
1272 if( poSession->Failed(
1273 OCIBindObject( hBindOrd, poSession->hError,
1274 poSession->hOrdinatesTDO,
1275 (dvoid **)&hOrdVARRAY, (ub4 *)0,
1276 (dvoid **)0, (ub4 *)0),
1277 "OCIBindObject(:ordinates)" ) )
1278 return OGRERR_FAILURE;
1279 }
1280
1281 /* -------------------------------------------------------------------- */
1282 /* Execute the insert. */
1283 /* -------------------------------------------------------------------- */
1284 if( oInsert.Execute( NULL ) != CE_None )
1285 return OGRERR_FAILURE;
1286 else
1287 return OGRERR_NONE;
1288 }
1289
1290
1291 /************************************************************************/
1292 /* GetExtent() */
1293 /************************************************************************/
1294
GetExtent(OGREnvelope * psExtent,int bForce)1295 OGRErr OGROCITableLayer::GetExtent(OGREnvelope *psExtent, int bForce)
1296
1297 {
1298 CPLAssert( NULL != psExtent );
1299
1300 OGRErr err = OGRERR_FAILURE;
1301
1302 if( EQUAL(GetGeometryColumn(),"") )
1303 {
1304 return OGRERR_NONE;
1305 }
1306
1307 /* -------------------------------------------------------------------- */
1308 /* Build query command. */
1309 /* -------------------------------------------------------------------- */
1310 CPLAssert( NULL != pszGeomName );
1311
1312 OGROCIStringBuf oCommand;
1313 oCommand.Appendf( 1000, "SELECT "
1314 "MIN(SDO_GEOM.SDO_MIN_MBR_ORDINATE(t.%s,m.DIMINFO,1)) AS MINX,"
1315 "MIN(SDO_GEOM.SDO_MIN_MBR_ORDINATE(t.%s,m.DIMINFO,2)) AS MINY,"
1316 "MAX(SDO_GEOM.SDO_MAX_MBR_ORDINATE(t.%s,m.DIMINFO,1)) AS MAXX,"
1317 "MAX(SDO_GEOM.SDO_MAX_MBR_ORDINATE(t.%s,m.DIMINFO,2)) AS MAXY "
1318 "FROM ALL_SDO_GEOM_METADATA m, ",
1319 pszGeomName, pszGeomName, pszGeomName, pszGeomName );
1320
1321 if( osOwner != "" )
1322 {
1323 oCommand.Appendf( 500, " %s.%s t ",
1324 osOwner.c_str(), osTableName.c_str() );
1325 }
1326 else
1327 {
1328 oCommand.Appendf( 500, " %s t ",
1329 osTableName.c_str() );
1330 }
1331
1332 oCommand.Appendf( 500, "WHERE m.TABLE_NAME = UPPER('%s') AND m.COLUMN_NAME = UPPER('%s')",
1333 osTableName.c_str(), pszGeomName );
1334
1335 if( osOwner != "" )
1336 {
1337 oCommand.Appendf( 500, " AND OWNER = UPPER('%s')", osOwner.c_str() );
1338 }
1339
1340 /* -------------------------------------------------------------------- */
1341 /* Execute query command. */
1342 /* -------------------------------------------------------------------- */
1343 OGROCISession *poSession = poDS->GetSession();
1344 CPLAssert( NULL != poSession );
1345
1346 OGROCIStatement oGetExtent( poSession );
1347
1348 if( oGetExtent.Execute( oCommand.GetString() ) == CE_None )
1349 {
1350 char **papszRow = oGetExtent.SimpleFetchRow();
1351
1352 if( papszRow != NULL
1353 && papszRow[0] != NULL && papszRow[1] != NULL
1354 && papszRow[2] != NULL && papszRow[3] != NULL )
1355 {
1356 psExtent->MinX = CPLAtof(papszRow[0]);
1357 psExtent->MinY = CPLAtof(papszRow[1]);
1358 psExtent->MaxX = CPLAtof(papszRow[2]);
1359 psExtent->MaxY = CPLAtof(papszRow[3]);
1360
1361 err = OGRERR_NONE;
1362 }
1363 }
1364
1365 /* -------------------------------------------------------------------- */
1366 /* Query spatial extent of layer using default, */
1367 /* but not optimized implementation. */
1368 /* -------------------------------------------------------------------- */
1369 if( err != OGRERR_NONE )
1370 {
1371 err = OGRLayer::GetExtent( psExtent, bForce );
1372 CPLDebug( "OCI",
1373 "Failing to query extent of %s using default GetExtent",
1374 osTableName.c_str() );
1375 }
1376
1377 return err;
1378 }
1379
1380 /************************************************************************/
1381 /* TestCapability() */
1382 /************************************************************************/
1383
TestCapability(const char * pszCap)1384 int OGROCITableLayer::TestCapability( const char * pszCap )
1385
1386 {
1387 if( EQUAL(pszCap,OLCSequentialWrite)
1388 || EQUAL(pszCap,OLCRandomWrite) )
1389 return bUpdateAccess;
1390
1391 else if( EQUAL(pszCap,OLCCreateField) )
1392 return bUpdateAccess;
1393
1394 else
1395 return OGROCILayer::TestCapability( pszCap );
1396 }
1397
1398 /************************************************************************/
1399 /* GetFeatureCount() */
1400 /* */
1401 /* If a spatial filter is in effect, we turn control over to */
1402 /* the generic counter. Otherwise we return the total count. */
1403 /* Eventually we should consider implementing a more efficient */
1404 /* way of counting features matching a spatial query. */
1405 /************************************************************************/
1406
GetFeatureCount(int bForce)1407 GIntBig OGROCITableLayer::GetFeatureCount( int bForce )
1408
1409 {
1410 /* -------------------------------------------------------------------- */
1411 /* Use a more brute force mechanism if we have a spatial query */
1412 /* in play. */
1413 /* -------------------------------------------------------------------- */
1414 if( m_poFilterGeom != NULL )
1415 return OGROCILayer::GetFeatureCount( bForce );
1416
1417 /* -------------------------------------------------------------------- */
1418 /* In theory it might be wise to cache this result, but it */
1419 /* won't be trivial to work out the lifetime of the value. */
1420 /* After all someone else could be adding records from another */
1421 /* application when working against a database. */
1422 /* -------------------------------------------------------------------- */
1423 OGROCISession *poSession = poDS->GetSession();
1424 OGROCIStatement oGetCount( poSession );
1425 char szCommand[1024];
1426 char **papszResult;
1427
1428 sprintf( szCommand, "SELECT COUNT(*) FROM %s %s",
1429 poFeatureDefn->GetName(), pszWHERE );
1430
1431 oGetCount.Execute( szCommand );
1432
1433 papszResult = oGetCount.SimpleFetchRow();
1434
1435 if( CSLCount(papszResult) < 1 )
1436 {
1437 CPLDebug( "OCI", "Fast get count failed, doing hard way." );
1438 return OGROCILayer::GetFeatureCount( bForce );
1439 }
1440
1441 return CPLAtoGIntBig(papszResult[0]);
1442 }
1443
1444 /************************************************************************/
1445 /* UpdateLayerExtents() */
1446 /************************************************************************/
1447
UpdateLayerExtents()1448 void OGROCITableLayer::UpdateLayerExtents()
1449
1450 {
1451 if( !bExtentUpdated )
1452 return;
1453
1454 bExtentUpdated = false;
1455
1456 /* -------------------------------------------------------------------- */
1457 /* Do we have existing layer extents we need to merge in to the */
1458 /* ones we collected as we created features? */
1459 /* -------------------------------------------------------------------- */
1460 bool bHaveOldExtent = false;
1461
1462 if( !bNewLayer && pszGeomName )
1463 {
1464 OGROCIStringBuf oCommand;
1465
1466 oCommand.Appendf(1000,
1467 "select min(case when r=1 then sdo_lb else null end) minx, min(case when r=2 then sdo_lb else null end) miny, "
1468 "min(case when r=1 then sdo_ub else null end) maxx, min(case when r=2 then sdo_ub else null end) maxy"
1469 " from (SELECT d.sdo_dimname, d.sdo_lb, sdo_ub, sdo_tolerance, rownum r"
1470 " FROM ALL_SDO_GEOM_METADATA m, table(m.diminfo) d"
1471 " where m.table_name = UPPER('%s') and m.COLUMN_NAME = UPPER('%s')",
1472 osTableName.c_str(), pszGeomName );
1473
1474 if( osOwner != "" )
1475 {
1476 oCommand.Appendf(500, " AND OWNER = UPPER('%s')", osOwner.c_str() );
1477 }
1478
1479 oCommand.Append(" ) ");
1480
1481 OGROCISession *poSession = poDS->GetSession();
1482 CPLAssert( NULL != poSession );
1483
1484 OGROCIStatement oGetExtent( poSession );
1485
1486 if( oGetExtent.Execute( oCommand.GetString() ) == CE_None )
1487 {
1488 char **papszRow = oGetExtent.SimpleFetchRow();
1489
1490 if( papszRow != NULL
1491 && papszRow[0] != NULL && papszRow[1] != NULL
1492 && papszRow[2] != NULL && papszRow[3] != NULL )
1493 {
1494 OGREnvelope sOldExtent;
1495
1496 bHaveOldExtent = true;
1497
1498 sOldExtent.MinX = CPLAtof(papszRow[0]);
1499 sOldExtent.MinY = CPLAtof(papszRow[1]);
1500 sOldExtent.MaxX = CPLAtof(papszRow[2]);
1501 sOldExtent.MaxY = CPLAtof(papszRow[3]);
1502
1503 if( sOldExtent.Contains( sExtent ) )
1504 {
1505 // nothing to do!
1506 sExtent = sOldExtent;
1507 bExtentUpdated = false;
1508 return;
1509 }
1510 else
1511 {
1512 sExtent.Merge( sOldExtent );
1513 }
1514 }
1515 }
1516 }
1517
1518 /* -------------------------------------------------------------------- */
1519 /* Establish the extents and resolution to use. */
1520 /* -------------------------------------------------------------------- */
1521 double dfResSize;
1522 double dfXMin, dfXMax, dfXRes;
1523 double dfYMin, dfYMax, dfYRes;
1524 double dfZMin, dfZMax, dfZRes;
1525
1526 if( sExtent.MaxX - sExtent.MinX > 400 )
1527 dfResSize = 0.001;
1528 else
1529 dfResSize = 0.0000001;
1530
1531 dfXMin = sExtent.MinX - dfResSize * 3;
1532 dfXMax = sExtent.MaxX + dfResSize * 3;
1533 dfXRes = dfResSize;
1534 ParseDIMINFO( "DIMINFO_X", &dfXMin, &dfXMax, &dfXRes );
1535
1536 dfYMin = sExtent.MinY - dfResSize * 3;
1537 dfYMax = sExtent.MaxY + dfResSize * 3;
1538 dfYRes = dfResSize;
1539 ParseDIMINFO( "DIMINFO_Y", &dfYMin, &dfYMax, &dfYRes );
1540
1541 dfZMin = -100000.0;
1542 dfZMax = 100000.0;
1543 dfZRes = 0.002;
1544 ParseDIMINFO( "DIMINFO_Z", &dfZMin, &dfZMax, &dfZRes );
1545
1546 /* -------------------------------------------------------------------- */
1547 /* If we already have an extent in the table, we will need to */
1548 /* update it in place. */
1549 /* -------------------------------------------------------------------- */
1550 OGROCIStringBuf sDimUpdate;
1551
1552 if( bHaveOldExtent )
1553 {
1554 sDimUpdate.Append( "UPDATE USER_SDO_GEOM_METADATA " );
1555 sDimUpdate.Append( "SET DIMINFO =" );
1556 sDimUpdate.Append( "MDSYS.SDO_DIM_ARRAY(" );
1557 sDimUpdate.Appendf(200,
1558 "MDSYS.SDO_DIM_ELEMENT('X',%.16g,%.16g,%.12g)",
1559 dfXMin, dfXMax, dfXRes );
1560 sDimUpdate.Appendf(200,
1561 ",MDSYS.SDO_DIM_ELEMENT('Y',%.16g,%.16g,%.12g)",
1562 dfYMin, dfYMax, dfYRes );
1563
1564 if( nDimension == 3 )
1565 {
1566 sDimUpdate.Appendf(200,
1567 ",MDSYS.SDO_DIM_ELEMENT('Z',%.16g,%.16g,%.12g)",
1568 dfZMin, dfZMax, dfZRes );
1569 }
1570
1571 sDimUpdate.Appendf(strlen(poFeatureDefn->GetName()) + 100,") WHERE TABLE_NAME = '%s'", poFeatureDefn->GetName());
1572
1573 }
1574 else
1575 {
1576 /* -------------------------------------------------------------------- */
1577 /* Prepare dimension update statement. */
1578 /* -------------------------------------------------------------------- */
1579 sDimUpdate.Append( "INSERT INTO USER_SDO_GEOM_METADATA VALUES " );
1580 sDimUpdate.Appendf( strlen(poFeatureDefn->GetName()) + 100,
1581 "('%s', '%s', ",
1582 poFeatureDefn->GetName(),
1583 pszGeomName );
1584
1585 sDimUpdate.Append( "MDSYS.SDO_DIM_ARRAY(" );
1586 sDimUpdate.Appendf(200,
1587 "MDSYS.SDO_DIM_ELEMENT('X',%.16g,%.16g,%.12g)",
1588 dfXMin, dfXMax, dfXRes );
1589 sDimUpdate.Appendf(200,
1590 ",MDSYS.SDO_DIM_ELEMENT('Y',%.16g,%.16g,%.12g)",
1591 dfYMin, dfYMax, dfYRes );
1592
1593 if( nDimension == 3 )
1594 {
1595 sDimUpdate.Appendf(200,
1596 ",MDSYS.SDO_DIM_ELEMENT('Z',%.16g,%.16g,%.12g)",
1597 dfZMin, dfZMax, dfZRes );
1598 }
1599
1600 if( nSRID == -1 )
1601 sDimUpdate.Append( "), NULL)" );
1602 else
1603 sDimUpdate.Appendf( 100, "), %d)", nSRID );
1604 }
1605
1606 /* -------------------------------------------------------------------- */
1607 /* Run the update/insert command. */
1608 /* -------------------------------------------------------------------- */
1609 OGROCIStatement oExecStatement( poDS->GetSession() );
1610
1611 oExecStatement.Execute( sDimUpdate.GetString() );
1612 }
1613
1614 /************************************************************************/
1615 /* AllocAndBindForWrite() */
1616 /************************************************************************/
1617
AllocAndBindForWrite()1618 int OGROCITableLayer::AllocAndBindForWrite()
1619
1620 {
1621 OGROCISession *poSession = poDS->GetSession();
1622 int i;
1623
1624 CPLAssert( nWriteCacheMax == 0 );
1625
1626 /* -------------------------------------------------------------------- */
1627 /* Decide on the number of rows we want to be able to cache at */
1628 /* a time. */
1629 /* -------------------------------------------------------------------- */
1630 nWriteCacheMax = 100;
1631
1632 /* -------------------------------------------------------------------- */
1633 /* Collect the INSERT statement. */
1634 /* -------------------------------------------------------------------- */
1635 OGROCIStringBuf oCmdBuf;
1636
1637 oCmdBuf.Append( "INSERT INTO \"" );
1638 oCmdBuf.Append( poFeatureDefn->GetName() );
1639 oCmdBuf.Append( "\"(\"" );
1640 oCmdBuf.Append( pszFIDName );
1641
1642 if (GetGeomType() != wkbNone)
1643 {
1644 oCmdBuf.Append( "\",\"" );
1645 oCmdBuf.Append( pszGeomName );
1646 }
1647
1648 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1649 {
1650 oCmdBuf.Append( "\",\"" );
1651 oCmdBuf.Append( poFeatureDefn->GetFieldDefn(i)->GetNameRef() );
1652 }
1653
1654 oCmdBuf.Append( "\") VALUES ( :fid " );
1655
1656 if (GetGeomType() != wkbNone)
1657 oCmdBuf.Append( ", :geometry" );
1658
1659 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1660 {
1661 oCmdBuf.Append( ", " );
1662 oCmdBuf.Appendf( 20, " :field_%d", i );
1663 }
1664
1665 oCmdBuf.Append( ") " );
1666
1667 /* -------------------------------------------------------------------- */
1668 /* Bind and Prepare it. */
1669 /* -------------------------------------------------------------------- */
1670 poBoundStatement = new OGROCIStatement( poSession );
1671 poBoundStatement->Prepare( oCmdBuf.GetString() );
1672
1673 /* -------------------------------------------------------------------- */
1674 /* Setup geometry indicator information. */
1675 /* -------------------------------------------------------------------- */
1676 if (GetGeomType() != wkbNone)
1677 {
1678 pasWriteGeomInd = (SDO_GEOMETRY_ind *)
1679 CPLCalloc(sizeof(SDO_GEOMETRY_ind),nWriteCacheMax);
1680
1681 papsWriteGeomIndMap = (SDO_GEOMETRY_ind **)
1682 CPLCalloc(sizeof(SDO_GEOMETRY_ind *),nWriteCacheMax);
1683
1684 for( i = 0; i < nWriteCacheMax; i++ )
1685 papsWriteGeomIndMap[i] = pasWriteGeomInd + i;
1686
1687 /* -------------------------------------------------------------------- */
1688 /* Setup all the required geometry objects, and the */
1689 /* corresponding indicator map. */
1690 /* -------------------------------------------------------------------- */
1691 pasWriteGeoms = (SDO_GEOMETRY_TYPE *)
1692 CPLCalloc( sizeof(SDO_GEOMETRY_TYPE), nWriteCacheMax);
1693 papsWriteGeomMap = (SDO_GEOMETRY_TYPE **)
1694 CPLCalloc( sizeof(SDO_GEOMETRY_TYPE *), nWriteCacheMax );
1695
1696 for( i = 0; i < nWriteCacheMax; i++ )
1697 papsWriteGeomMap[i] = pasWriteGeoms + i;
1698
1699 /* -------------------------------------------------------------------- */
1700 /* Allocate VARRAYs for the elem_info and ordinates. */
1701 /* -------------------------------------------------------------------- */
1702 for( i = 0; i < nWriteCacheMax; i++ )
1703 {
1704 if( poSession->Failed(
1705 OCIObjectNew( poSession->hEnv, poSession->hError,
1706 poSession->hSvcCtx, OCI_TYPECODE_VARRAY,
1707 poSession->hElemInfoTDO, (dvoid *)NULL,
1708 OCI_DURATION_SESSION,
1709 FALSE,
1710 (dvoid **) &(pasWriteGeoms[i].sdo_elem_info)),
1711 "OCIObjectNew(elem_info)") )
1712 return FALSE;
1713
1714 if( poSession->Failed(
1715 OCIObjectNew( poSession->hEnv, poSession->hError,
1716 poSession->hSvcCtx, OCI_TYPECODE_VARRAY,
1717 poSession->hOrdinatesTDO, (dvoid *)NULL,
1718 OCI_DURATION_SESSION,
1719 FALSE,
1720 (dvoid **) &(pasWriteGeoms[i].sdo_ordinates)),
1721 "OCIObjectNew(ordinates)") )
1722 return FALSE;
1723 }
1724
1725 /* -------------------------------------------------------------------- */
1726 /* Bind the geometry column. */
1727 /* -------------------------------------------------------------------- */
1728 if( poBoundStatement->BindObject(
1729 ":geometry", papsWriteGeomMap, poSession->hGeometryTDO,
1730 (void**) papsWriteGeomIndMap) != CE_None )
1731 return FALSE;
1732 }
1733
1734 /* -------------------------------------------------------------------- */
1735 /* Bind the FID column. */
1736 /* -------------------------------------------------------------------- */
1737 panWriteFIDs = (int *) CPLMalloc(sizeof(int) * nWriteCacheMax );
1738
1739 if( poBoundStatement->BindScalar( ":fid", panWriteFIDs, sizeof(int),
1740 SQLT_INT ) != CE_None )
1741 return FALSE;
1742
1743 /* -------------------------------------------------------------------- */
1744 /* Allocate each of the column data bind arrays. */
1745 /* -------------------------------------------------------------------- */
1746
1747 papWriteFields = (void **)
1748 CPLMalloc(sizeof(void*) * poFeatureDefn->GetFieldCount() );
1749 papaeWriteFieldInd = (OCIInd **)
1750 CPLCalloc(sizeof(OCIInd*),poFeatureDefn->GetFieldCount() );
1751
1752 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1753 {
1754 OGRFieldDefn *poFldDefn = poFeatureDefn->GetFieldDefn(i);
1755 char szFieldPlaceholderName[80];
1756
1757 sprintf( szFieldPlaceholderName, ":field_%d", i );
1758
1759 papaeWriteFieldInd[i] = (OCIInd *)
1760 CPLCalloc(sizeof(OCIInd), nWriteCacheMax );
1761
1762 if( poFldDefn->GetType() == OFTInteger )
1763 {
1764 papWriteFields[i] =
1765 (void *) CPLCalloc( sizeof(int), nWriteCacheMax );
1766
1767 if( poBoundStatement->BindScalar(
1768 szFieldPlaceholderName, papWriteFields[i],
1769 sizeof(int), SQLT_INT, papaeWriteFieldInd[i] ) != CE_None )
1770 return FALSE;
1771 }
1772 else if( poFldDefn->GetType() == OFTInteger64 )
1773 {
1774 papWriteFields[i] =
1775 (void *) CPLCalloc( sizeof(GIntBig), nWriteCacheMax );
1776
1777 if( poBoundStatement->BindScalar(
1778 szFieldPlaceholderName, papWriteFields[i],
1779 sizeof(GIntBig), SQLT_INT, papaeWriteFieldInd[i] ) != CE_None )
1780 return FALSE;
1781 }
1782 else if( poFldDefn->GetType() == OFTReal )
1783 {
1784 papWriteFields[i] = (void *) CPLCalloc( sizeof(double),
1785 nWriteCacheMax );
1786
1787 if( poBoundStatement->BindScalar(
1788 szFieldPlaceholderName, papWriteFields[i],
1789 sizeof(double), SQLT_FLT, papaeWriteFieldInd[i] ) != CE_None )
1790 return FALSE;
1791 }
1792 else
1793 {
1794 int nEachBufSize = 4001;
1795
1796 if( poFldDefn->GetType() == OFTString
1797 && poFldDefn->GetWidth() != 0 )
1798 nEachBufSize = poFldDefn->GetWidth() + 1;
1799
1800 papWriteFields[i] =
1801 (void *) CPLCalloc( nEachBufSize, nWriteCacheMax );
1802
1803 if( poBoundStatement->BindScalar(
1804 szFieldPlaceholderName, papWriteFields[i],
1805 nEachBufSize, SQLT_STR, papaeWriteFieldInd[i]) != CE_None )
1806 return FALSE;
1807 }
1808 }
1809
1810 return TRUE;
1811 }
1812
1813 /************************************************************************/
1814 /* BoundCreateFeature() */
1815 /************************************************************************/
1816
BoundCreateFeature(OGRFeature * poFeature)1817 OGRErr OGROCITableLayer::BoundCreateFeature( OGRFeature *poFeature )
1818
1819 {
1820 OGROCISession *poSession = poDS->GetSession();
1821 int iCache, i;
1822 OGRErr eErr;
1823 OCINumber oci_number;
1824
1825 /* If an unset field has a default value, the current implementation */
1826 /* of BoundCreateFeature() doesn't work. */
1827 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1828 {
1829 if( !poFeature->IsFieldSet( i ) &&
1830 poFeature->GetFieldDefnRef(i)->GetDefault() != NULL )
1831 {
1832 FlushPendingFeatures();
1833 return UnboundCreateFeature(poFeature);
1834 }
1835 }
1836
1837 if( !poFeature->Validate( OGR_F_VAL_NULL | OGR_F_VAL_ALLOW_NULL_WHEN_DEFAULT, TRUE ) )
1838 return OGRERR_FAILURE;
1839
1840 iCache = nWriteCacheUsed;
1841
1842 /* -------------------------------------------------------------------- */
1843 /* Initiate the Insert */
1844 /* -------------------------------------------------------------------- */
1845 if( nWriteCacheMax == 0 )
1846 {
1847 if( !AllocAndBindForWrite() )
1848 return OGRERR_FAILURE;
1849 }
1850
1851 /* -------------------------------------------------------------------- */
1852 /* Set the geometry */
1853 /* -------------------------------------------------------------------- */
1854 if( poFeature->GetGeometryRef() != NULL )
1855 {
1856 SDO_GEOMETRY_TYPE *psGeom = pasWriteGeoms + iCache;
1857 SDO_GEOMETRY_ind *psInd = pasWriteGeomInd + iCache;
1858 OGRGeometry *poGeometry = poFeature->GetGeometryRef();
1859 int nGType;
1860
1861 psInd->_atomic = OCI_IND_NOTNULL;
1862
1863 if( nSRID == -1 )
1864 psInd->sdo_srid = OCI_IND_NULL;
1865 else
1866 {
1867 psInd->sdo_srid = OCI_IND_NOTNULL;
1868 OCINumberFromInt( poSession->hError, &nSRID,
1869 (uword)sizeof(int), OCI_NUMBER_SIGNED,
1870 &(psGeom->sdo_srid) );
1871 }
1872
1873 /* special more efficient case for simple points */
1874 if( wkbFlatten(poGeometry->getGeometryType()) == wkbPoint )
1875 {
1876 OGRPoint *poPoint = (OGRPoint *) poGeometry;
1877 double dfValue;
1878
1879 psInd->sdo_point._atomic = OCI_IND_NOTNULL;
1880 psInd->sdo_elem_info = OCI_IND_NULL;
1881 psInd->sdo_ordinates = OCI_IND_NULL;
1882
1883 dfValue = poPoint->getX();
1884 OCINumberFromReal( poSession->hError, &dfValue,
1885 (uword)sizeof(double),
1886 &(psGeom->sdo_point.x) );
1887
1888 dfValue = poPoint->getY();
1889 OCINumberFromReal( poSession->hError, &dfValue,
1890 (uword)sizeof(double),
1891 &(psGeom->sdo_point.y) );
1892
1893 if( nDimension == 2 )
1894 {
1895 nGType = 2001;
1896 psInd->sdo_point.z = OCI_IND_NULL;
1897 }
1898 else
1899 {
1900 nGType = 3001;
1901 psInd->sdo_point.z = OCI_IND_NOTNULL;
1902
1903 dfValue = poPoint->getZ();
1904 OCINumberFromReal( poSession->hError, &dfValue,
1905 (uword)sizeof(double),
1906 &(psGeom->sdo_point.z) );
1907 }
1908 }
1909 else
1910 {
1911 psInd->sdo_point._atomic = OCI_IND_NULL;
1912 psInd->sdo_elem_info = OCI_IND_NOTNULL;
1913 psInd->sdo_ordinates = OCI_IND_NOTNULL;
1914
1915 eErr = TranslateToSDOGeometry( poFeature->GetGeometryRef(),
1916 &nGType );
1917
1918 if( eErr != OGRERR_NONE )
1919 return eErr;
1920
1921 /* Clear the existing eleminfo and ordinates arrays */
1922 sb4 nOldCount;
1923
1924 OCICollSize( poSession->hEnv, poSession->hError,
1925 psGeom->sdo_elem_info, &nOldCount );
1926 OCICollTrim( poSession->hEnv, poSession->hError,
1927 nOldCount, psGeom->sdo_elem_info );
1928
1929 OCICollSize( poSession->hEnv, poSession->hError,
1930 psGeom->sdo_ordinates, &nOldCount );
1931 OCICollTrim( poSession->hEnv, poSession->hError,
1932 nOldCount, psGeom->sdo_ordinates );
1933
1934 // Prepare the VARRAY of element values.
1935 for (i = 0; i < nElemInfoCount; i++)
1936 {
1937 OCINumberFromInt( poSession->hError,
1938 (dvoid *) (panElemInfo + i),
1939 (uword)sizeof(int), OCI_NUMBER_SIGNED,
1940 &oci_number );
1941
1942 OCICollAppend( poSession->hEnv, poSession->hError,
1943 (dvoid *) &oci_number,
1944 (dvoid *)0, psGeom->sdo_elem_info );
1945 }
1946
1947 // Prepare the VARRAY of ordinate values.
1948 for (i = 0; i < nOrdinalCount; i++)
1949 {
1950 OCINumberFromReal( poSession->hError,
1951 (dvoid *) (padfOrdinals + i),
1952 (uword)sizeof(double), &oci_number );
1953 OCICollAppend( poSession->hEnv, poSession->hError,
1954 (dvoid *) &oci_number,
1955 (dvoid *)0, psGeom->sdo_ordinates );
1956 }
1957 }
1958
1959 psInd->sdo_gtype = OCI_IND_NOTNULL;
1960 OCINumberFromInt( poSession->hError, &nGType,
1961 (uword)sizeof(int), OCI_NUMBER_SIGNED,
1962 &(psGeom->sdo_gtype) );
1963 }
1964 else if( pasWriteGeomInd != NULL )
1965 {
1966 SDO_GEOMETRY_ind *psInd = pasWriteGeomInd + iCache;
1967 psInd->_atomic = OCI_IND_NULL;
1968 psInd->sdo_srid = OCI_IND_NULL;
1969 psInd->sdo_point._atomic = OCI_IND_NULL;
1970 psInd->sdo_elem_info = OCI_IND_NULL;
1971 psInd->sdo_ordinates = OCI_IND_NULL;
1972 psInd->sdo_gtype = OCI_IND_NULL;
1973 }
1974
1975 /* -------------------------------------------------------------------- */
1976 /* Set the FID. */
1977 /* -------------------------------------------------------------------- */
1978 if( poFeature->GetFID() == OGRNullFID )
1979 {
1980 if( iNextFIDToWrite < 0 )
1981 {
1982 iNextFIDToWrite = GetMaxFID() + 1;
1983 }
1984
1985 poFeature->SetFID( iNextFIDToWrite++ );
1986 }
1987
1988 panWriteFIDs[iCache] = poFeature->GetFID();
1989
1990 /* -------------------------------------------------------------------- */
1991 /* Set the other fields. */
1992 /* -------------------------------------------------------------------- */
1993 for( i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
1994 {
1995 if( !poFeature->IsFieldSet( i ) )
1996 {
1997 papaeWriteFieldInd[i][iCache] = OCI_IND_NULL;
1998 continue;
1999 }
2000
2001 papaeWriteFieldInd[i][iCache] = OCI_IND_NOTNULL;
2002
2003 OGRFieldDefn *poFldDefn = poFeatureDefn->GetFieldDefn(i);
2004
2005 if( poFldDefn->GetType() == OFTInteger )
2006 ((int *) (papWriteFields[i]))[iCache] =
2007 poFeature->GetFieldAsInteger( i );
2008
2009 else if( poFldDefn->GetType() == OFTInteger64 )
2010 ((GIntBig *) (papWriteFields[i]))[iCache] =
2011 poFeature->GetFieldAsInteger64( i );
2012
2013 else if( poFldDefn->GetType() == OFTReal )
2014 ((double *) (papWriteFields[i]))[iCache] =
2015 poFeature->GetFieldAsDouble( i );
2016
2017 else
2018 {
2019 int nEachBufSize = 4001, nLen;
2020 const char *pszStrValue = poFeature->GetFieldAsString(i);
2021
2022 if( poFldDefn->GetType() == OFTString
2023 && poFldDefn->GetWidth() != 0 )
2024 nEachBufSize = poFldDefn->GetWidth() + 1;
2025
2026 nLen = strlen(pszStrValue);
2027 if( nLen > nEachBufSize-1 )
2028 nLen = nEachBufSize-1;
2029
2030 char *pszTarget = ((char*)papWriteFields[i]) + iCache*nEachBufSize;
2031 strncpy( pszTarget, pszStrValue, nLen );
2032 pszTarget[nLen] = '\0';
2033 }
2034 }
2035
2036 /* -------------------------------------------------------------------- */
2037 /* Do we need to flush out a full set of rows? */
2038 /* -------------------------------------------------------------------- */
2039 nWriteCacheUsed++;
2040
2041 if( nWriteCacheUsed == nWriteCacheMax )
2042 return FlushPendingFeatures();
2043 else
2044 return OGRERR_NONE;
2045 }
2046
2047 /************************************************************************/
2048 /* FlushPendingFeatures() */
2049 /************************************************************************/
2050
FlushPendingFeatures()2051 OGRErr OGROCITableLayer::FlushPendingFeatures()
2052
2053 {
2054 OGROCISession *poSession = poDS->GetSession();
2055
2056 if( nWriteCacheUsed > 0 )
2057 {
2058 CPLDebug( "OCI", "Flushing %d features on layer %s",
2059 nWriteCacheUsed, poFeatureDefn->GetName() );
2060
2061 if( poSession->Failed(
2062 OCIStmtExecute( poSession->hSvcCtx,
2063 poBoundStatement->GetStatement(),
2064 poSession->hError, (ub4) nWriteCacheUsed,
2065 (ub4) 0,
2066 (OCISnapshot *)NULL, (OCISnapshot *)NULL,
2067 (ub4) OCI_COMMIT_ON_SUCCESS ),
2068 "OCIStmtExecute" ) )
2069 {
2070 nWriteCacheUsed = 0;
2071 return OGRERR_FAILURE;
2072 }
2073 else
2074 {
2075 nWriteCacheUsed = 0;
2076 return OGRERR_NONE;
2077 }
2078 }
2079 else
2080 return OGRERR_NONE;
2081 }
2082
2083 /************************************************************************/
2084 /* SyncToDisk() */
2085 /* */
2086 /* Perhaps we should also be putting the metadata into a */
2087 /* useable state? */
2088 /************************************************************************/
2089
SyncToDisk()2090 OGRErr OGROCITableLayer::SyncToDisk()
2091
2092 {
2093 OGRErr eErr = FlushPendingFeatures();
2094
2095 UpdateLayerExtents();
2096
2097 CreateSpatialIndex();
2098
2099 bNewLayer = FALSE;
2100
2101 return eErr;
2102 }
2103
2104 /*************************************************************************/
2105 /* CreateSpatialIndex() */
2106 /*************************************************************************/
2107
CreateSpatialIndex()2108 void OGROCITableLayer::CreateSpatialIndex()
2109
2110 {
2111 /* -------------------------------------------------------------------- */
2112 /* For new layers we try to create a spatial index. */
2113 /* -------------------------------------------------------------------- */
2114 if( bNewLayer && sExtent.IsInit() )
2115 {
2116 /* -------------------------------------------------------------------- */
2117 /* If the user has disabled INDEX support then don't create the */
2118 /* index. */
2119 /* -------------------------------------------------------------------- */
2120 if( !CSLFetchBoolean( papszOptions, "SPATIAL_INDEX", TRUE ) ||
2121 !CSLFetchBoolean( papszOptions, "INDEX", TRUE ) )
2122 return;
2123
2124 /* -------------------------------------------------------------------- */
2125 /* Establish an index name. For some reason Oracle 8.1.7 does */
2126 /* not support spatial index names longer than 18 characters so */
2127 /* we magic up an index name if it would be too long. */
2128 /* -------------------------------------------------------------------- */
2129 char szIndexName[20];
2130
2131 if( strlen(poFeatureDefn->GetName()) < 15 )
2132 sprintf( szIndexName, "%s_idx", poFeatureDefn->GetName() );
2133 else if( strlen(poFeatureDefn->GetName()) < 17 )
2134 sprintf( szIndexName, "%si", poFeatureDefn->GetName() );
2135 else
2136 {
2137 int i, nHash = 0;
2138 const char *pszSrcName = poFeatureDefn->GetName();
2139
2140 for( i = 0; pszSrcName[i] != '\0'; i++ )
2141 nHash = (nHash + i * pszSrcName[i]) % 987651;
2142
2143 sprintf( szIndexName, "OSI_%d", nHash );
2144 }
2145
2146 poDS->GetSession()->CleanName( szIndexName );
2147
2148 /* -------------------------------------------------------------------- */
2149 /* Try creating an index on the table now. Use a simple 5 */
2150 /* level quadtree based index. Would R-tree be a better default? */
2151 /* -------------------------------------------------------------------- */
2152 OGROCIStringBuf sIndexCmd;
2153 OGROCIStatement oExecStatement( poDS->GetSession() );
2154
2155
2156 sIndexCmd.Appendf( 10000, "CREATE INDEX \"%s\" ON %s(\"%s\") "
2157 "INDEXTYPE IS MDSYS.SPATIAL_INDEX ",
2158 szIndexName,
2159 poFeatureDefn->GetName(),
2160 pszGeomName );
2161
2162 int bAddLayerGType = CSLTestBoolean(
2163 CSLFetchNameValueDef( papszOptions, "ADD_LAYER_GTYPE", "YES") ) &&
2164 GetGeomType() != wkbUnknown;
2165
2166 CPLString osParams(CSLFetchNameValueDef(papszOptions,"INDEX_PARAMETERS", ""));
2167 if( bAddLayerGType || osParams.size() != 0 )
2168 {
2169 sIndexCmd.Append( " PARAMETERS( '" );
2170 if( osParams.size() != 0 )
2171 sIndexCmd.Append( osParams.c_str() );
2172 if( bAddLayerGType &&
2173 osParams.ifind("LAYER_GTYPE") == std::string::npos )
2174 {
2175 if( osParams.size() != 0 )
2176 sIndexCmd.Append( ", " );
2177 sIndexCmd.Append( "LAYER_GTYPE=" );
2178 if( wkbFlatten(GetGeomType()) == wkbPoint )
2179 sIndexCmd.Append( "POINT" );
2180 else if( wkbFlatten(GetGeomType()) == wkbLineString )
2181 sIndexCmd.Append( "LINE" );
2182 else if( wkbFlatten(GetGeomType()) == wkbPolygon )
2183 sIndexCmd.Append( "POLYGON" );
2184 else if( wkbFlatten(GetGeomType()) == wkbMultiPoint )
2185 sIndexCmd.Append( "MULTIPOINT" );
2186 else if( wkbFlatten(GetGeomType()) == wkbMultiLineString )
2187 sIndexCmd.Append( "MULTILINE" );
2188 else if( wkbFlatten(GetGeomType()) == wkbMultiPolygon )
2189 sIndexCmd.Append( "MULTIPOLYGON" );
2190 else
2191 sIndexCmd.Append( "COLLECTION" );
2192 }
2193 sIndexCmd.Append( "' )" );
2194 }
2195
2196 if( oExecStatement.Execute( sIndexCmd.GetString() ) != CE_None )
2197 {
2198 CPLString osDropCommand;
2199 osDropCommand.Printf( "DROP INDEX \"%s\"", szIndexName );
2200 oExecStatement.Execute( osDropCommand );
2201 }
2202 }
2203 }
2204
GetMaxFID()2205 int OGROCITableLayer::GetMaxFID()
2206 {
2207 if( pszFIDName == NULL )
2208 return 0;
2209
2210 OGROCIStringBuf sCmd;
2211 OGROCIStatement oSelect( poDS->GetSession() );
2212
2213 sCmd.Appendf( 10000, "SELECT MAX(\"%s\") FROM \"%s\"",
2214 pszFIDName,
2215 poFeatureDefn->GetName()
2216 );
2217
2218 oSelect.Execute( sCmd.GetString() );
2219
2220 char **papszResult = oSelect.SimpleFetchRow();
2221 return CSLCount(papszResult) == 1 ? atoi( papszResult[0] ) : 0;
2222 }
2223