1 /******************************************************************************
2 *
3 * Project: OpenGIS Simple Features Reference Implementation
4 * Purpose: Implements OGRIDBTableLayer class, access to an existing table
5 * (based on ODBC and PG drivers).
6 * Author: Oleg Semykin, oleg.semykin@gmail.com
7 *
8 ******************************************************************************
9 * Copyright (c) 2006, Oleg Semykin
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 "cpl_conv.h"
31 #include "cpl_string.h"
32 #include "ogr_idb.h"
33
34 CPL_CVSID("$Id: ogridbtablelayer.cpp 417b66cdf50174fe8d59833c93710813f205d9ba 2020-08-30 12:18:19 +0200 Even Rouault $")
35 /************************************************************************/
36 /* OGRIDBTableLayer() */
37 /************************************************************************/
38
OGRIDBTableLayer(OGRIDBDataSource * poDSIn)39 OGRIDBTableLayer::OGRIDBTableLayer( OGRIDBDataSource *poDSIn )
40
41 {
42 poDS = poDSIn;
43
44 pszQuery = nullptr;
45
46 bUpdateAccess = TRUE;
47 bHaveSpatialExtents = FALSE;
48
49 iNextShapeId = 0;
50
51 poFeatureDefn = nullptr;
52 }
53
54 /************************************************************************/
55 /* ~OGRIDBTableLayer() */
56 /************************************************************************/
57
~OGRIDBTableLayer()58 OGRIDBTableLayer::~OGRIDBTableLayer()
59
60 {
61 CPLFree( pszQuery );
62 ClearQuery();
63 }
64
65 /************************************************************************/
66 /* Initialize() */
67 /************************************************************************/
68
Initialize(const char * pszTableName,const char * pszGeomCol,int bUpdate)69 CPLErr OGRIDBTableLayer::Initialize( const char *pszTableName,
70 const char *pszGeomCol,
71 int bUpdate )
72
73 {
74 bUpdateAccess = bUpdate;
75
76 ITConnection *poConn = poDS->GetConnection();
77
78 if ( pszFIDColumn )
79 {
80 CPLFree( pszFIDColumn );
81 pszFIDColumn = nullptr;
82 }
83
84 /* -------------------------------------------------------------------- */
85 /* Do we have a simple primary key? */
86 /* -------------------------------------------------------------------- */
87 if ( pszFIDColumn== nullptr )
88 {
89 ITCursor oGetKey( *poConn );
90
91 CPLString osSql =
92 " select sc.colname"
93 " from syscolumns sc, sysindexes si, systables st"
94 " where st.tabid = si.tabid"
95 " and st.tabid = sc.tabid"
96 " and si.idxtype = 'U'"
97 " and sc.colno = si.part1"
98 " and si.part2 = 0" // only one-column keys
99 " and st.tabname='";
100 osSql += pszTableName;
101 osSql += "'";
102
103 if( oGetKey.Prepare( osSql.c_str() ) &&
104 oGetKey.Open(ITCursor::ReadOnly) )
105 {
106 ITValue * poVal = oGetKey.Fetch();
107 if ( poVal && poVal->IsNull() == false )
108 {
109 pszFIDColumn = CPLStrdup(poVal->Printable());
110 poVal->Release();
111 }
112
113 if( oGetKey.Fetch() ) // more than one field in key!
114 {
115 CPLFree( pszFIDColumn );
116 pszFIDColumn = nullptr;
117
118 CPLDebug("OGR_IDB", "Table %s has multiple primary key fields,"
119 " ignoring them all.", pszTableName );
120 }
121 }
122 }
123
124 /* -------------------------------------------------------------------- */
125 /* Have we been provided a geometry column? */
126 /* -------------------------------------------------------------------- */
127 CPLFree( pszGeomColumn );
128 if( pszGeomCol== nullptr )
129 pszGeomColumn = nullptr;
130 else
131 pszGeomColumn = CPLStrdup( pszGeomCol );
132
133 /* -------------------------------------------------------------------- */
134 /* Get the column definitions for this table. */
135 /* -------------------------------------------------------------------- */
136 ITCursor oGetCol( *poConn );
137 CPLErr eErr;
138
139 CPLString sql;
140 sql.Printf( "select * from %s where 1=0", pszTableName );
141 if( ! oGetCol.Prepare( sql.c_str() ) ||
142 ! oGetCol.Open(ITCursor::ReadOnly) )
143 return CE_Failure;
144
145 eErr = BuildFeatureDefn( pszTableName, &oGetCol );
146 if( eErr != CE_None )
147 return eErr;
148
149 if( poFeatureDefn->GetFieldCount() == 0 )
150 {
151 CPLError( CE_Failure, CPLE_AppDefined,
152 "No column definitions found for table '%s', layer not usable.",
153 pszTableName );
154 return CE_Failure;
155 }
156
157 /* -------------------------------------------------------------------- */
158 /* Do we have XMIN, YMIN, XMAX, YMAX extent fields? */
159 /* -------------------------------------------------------------------- */
160 if( poFeatureDefn->GetFieldIndex( "XMIN" ) != -1
161 && poFeatureDefn->GetFieldIndex( "XMAX" ) != -1
162 && poFeatureDefn->GetFieldIndex( "YMIN" ) != -1
163 && poFeatureDefn->GetFieldIndex( "YMAX" ) != -1 )
164 {
165 bHaveSpatialExtents = TRUE;
166 CPLDebug( "OGR_IDB", "Table %s has geometry extent fields.",
167 pszTableName );
168 }
169
170 /* -------------------------------------------------------------------- */
171 /* If we got a geometry column, does it exist? Is it binary? */
172 /* -------------------------------------------------------------------- */
173 if( pszGeomColumn != nullptr )
174 {
175 int iColumn = oGetCol.RowType()->ColumnId( pszGeomColumn );
176 if( iColumn < 0 )
177 {
178 CPLError( CE_Failure, CPLE_AppDefined,
179 "Column %s requested for geometry, but it does not exist.",
180 pszGeomColumn );
181 CPLFree( pszGeomColumn );
182 pszGeomColumn = nullptr;
183 }
184 bGeomColumnWKB = TRUE;
185 /*else
186 {
187 if( ITCursor::GetTypeMapping(
188 oGetCol.GetColType( iColumn )) == SQL_C_BINARY )
189 bGeomColumnWKB = TRUE;
190 }*/
191 }
192
193 return CE_None;
194 }
195
196 /************************************************************************/
197 /* ClearQuery() */
198 /************************************************************************/
199
ClearQuery()200 void OGRIDBTableLayer::ClearQuery()
201
202 {
203 if( m_poCurr != nullptr )
204 {
205 m_poCurr->Close();
206 delete m_poCurr;
207 m_poCurr = nullptr;
208 }
209 }
210
211 /************************************************************************/
212 /* GetQuery() */
213 /************************************************************************/
214
GetQuery()215 ITCursor *OGRIDBTableLayer::GetQuery()
216
217 {
218 if( m_poCurr== nullptr )
219 ResetQuery();
220
221 return m_poCurr;
222 }
223
224 /************************************************************************/
225 /* ResetQuery() */
226 /************************************************************************/
227
ResetQuery()228 OGRErr OGRIDBTableLayer::ResetQuery()
229
230 {
231 ClearQuery();
232
233 iNextShapeId = 0;
234
235 m_poCurr = new ITCursor( *poDS->GetConnection() );
236
237 // Create list of fields
238 CPLString osFields;
239
240 if ( pszGeomColumn )
241 {
242 if ( ! osFields.empty() )
243 osFields += ",";
244
245 osFields += "st_asbinary(";
246 osFields += pszGeomColumn;
247 osFields += ") as ";
248 osFields += pszGeomColumn;
249 }
250
251 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
252 {
253 if ( ! osFields.empty() )
254 osFields += ",";
255
256 osFields += poFeatureDefn->GetFieldDefn(i)->GetNameRef();
257 }
258
259 CPLString sql;
260
261 sql += "SELECT ";
262 sql += osFields;
263 sql += " FROM ";
264 sql += poFeatureDefn->GetName();
265
266 /* Append attribute query if we have it */
267 if( pszQuery != nullptr )
268 {
269 sql += " WHERE ";
270 sql += pszQuery;
271 }
272
273 /* If we have a spatial filter, and per record extents, query on it */
274 if( m_poFilterGeom != nullptr && bHaveSpatialExtents )
275 {
276 if( pszQuery== nullptr )
277 sql += " WHERE";
278 else
279 sql += " AND";
280
281 CPLString sqlTmp;
282 sqlTmp.Printf( "%s XMAX > %.8f AND XMIN < %.8f"
283 " AND YMAX > %.8f AND YMIN < %.8f",
284 sql.c_str(),
285 m_sFilterEnvelope.MinX, m_sFilterEnvelope.MaxX,
286 m_sFilterEnvelope.MinY, m_sFilterEnvelope.MaxY );
287 sql = sqlTmp;
288 }
289 /* If we have a spatial filter and GeomColumn, query using st_intersects function */
290 else if( m_poFilterGeom != nullptr && pszGeomColumn )
291 {
292 if( pszQuery== nullptr )
293 sql += " WHERE";
294 else
295 sql += " AND";
296
297 CPLString sqlTmp;
298 sqlTmp.Printf(
299 "%s st_intersects(st_geomfromtext('POLYGON((%.8f %.8f, %.8f %.8f, %.8f %.8f, %.8f %.8f, %.8f %.8f))',0),%s)",
300 sql.c_str(),
301 m_sFilterEnvelope.MinX, m_sFilterEnvelope.MinY,
302 m_sFilterEnvelope.MaxX, m_sFilterEnvelope.MinY,
303 m_sFilterEnvelope.MaxX, m_sFilterEnvelope.MaxY,
304 m_sFilterEnvelope.MinX, m_sFilterEnvelope.MaxY,
305 m_sFilterEnvelope.MinX, m_sFilterEnvelope.MinY, pszGeomColumn );
306 sql = sqlTmp;
307 }
308
309 CPLDebug( "OGR_IDB", "Exec(%s)", sql.c_str() );
310 if( m_poCurr->Prepare( sql.c_str() ) &&
311 m_poCurr->Open(ITCursor::ReadOnly) )
312 {
313 return OGRERR_NONE;
314 }
315 else
316 {
317 delete m_poCurr;
318 m_poCurr = nullptr;
319 return OGRERR_FAILURE;
320 }
321 }
322
323 /************************************************************************/
324 /* ResetReading() */
325 /************************************************************************/
326
ResetReading()327 void OGRIDBTableLayer::ResetReading()
328
329 {
330 ClearQuery();
331 OGRIDBLayer::ResetReading();
332 }
333
334 /************************************************************************/
335 /* GetFeature() */
336 /************************************************************************/
337
GetFeature(GIntBig nFeatureId)338 OGRFeature *OGRIDBTableLayer::GetFeature( GIntBig nFeatureId )
339
340 {
341 if( pszFIDColumn== nullptr )
342 return OGRIDBLayer::GetFeature( nFeatureId );
343
344 ClearQuery();
345
346 iNextShapeId = nFeatureId;
347
348 m_poCurr = new ITCursor( *poDS->GetConnection() );
349
350 // Create list of fields
351 CPLString osFields;
352
353 if ( poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
354 osFields += pszFIDColumn;
355
356 if ( pszGeomColumn )
357 {
358 if ( ! osFields.empty() )
359 osFields += ",";
360
361 osFields += "st_asbinary(";
362 osFields += pszGeomColumn;
363 osFields += ") as ";
364 osFields += pszGeomColumn;
365 }
366
367 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
368 {
369 if ( ! osFields.empty() )
370 osFields += ",";
371
372 osFields += poFeatureDefn->GetFieldDefn(i)->GetNameRef();
373 }
374
375 CPLString sql;
376
377 sql.Printf( "SELECT %s FROM %s WHERE %s = " CPL_FRMT_GIB,
378 osFields.c_str(), poFeatureDefn->GetName(),
379 pszFIDColumn, nFeatureId );
380
381 CPLDebug( "OGR_IDB", "ExecuteSQL(%s)", sql.c_str() );
382 if( !m_poCurr->Prepare( sql.c_str() ) ||
383 !m_poCurr->Open(ITCursor::ReadOnly) )
384 {
385 delete m_poCurr;
386 m_poCurr = nullptr;
387 return nullptr;
388 }
389
390 return GetNextRawFeature();
391 }
392
393 /************************************************************************/
394 /* SetAttributeFilter() */
395 /************************************************************************/
396
SetAttributeFilter(const char * pszQueryIn)397 OGRErr OGRIDBTableLayer::SetAttributeFilter( const char *pszQueryIn )
398
399 {
400 CPLFree(m_pszAttrQueryString);
401 m_pszAttrQueryString = (pszQueryIn) ? CPLStrdup(pszQueryIn) : nullptr;
402
403 if( (pszQueryIn== nullptr && this->pszQuery == nullptr)
404 || (pszQueryIn != nullptr && this->pszQuery != nullptr
405 && EQUAL(pszQueryIn,this->pszQuery)) )
406 return OGRERR_NONE;
407
408 CPLFree( this->pszQuery );
409 this->pszQuery = CPLStrdup( pszQueryIn );
410
411 ClearQuery();
412
413 return OGRERR_NONE;
414 }
415
416 /************************************************************************/
417 /* TestCapability() */
418 /************************************************************************/
419
TestCapability(const char * pszCap)420 int OGRIDBTableLayer::TestCapability( const char * pszCap )
421
422 {
423 if( EQUAL(pszCap,OLCSequentialWrite) ||
424 EQUAL(pszCap,OLCRandomWrite) )
425 return bUpdateAccess;
426
427 else if( EQUAL(pszCap,OLCRandomRead) )
428 return TRUE;
429
430 else
431 return OGRIDBLayer::TestCapability( pszCap );
432 }
433
434 /************************************************************************/
435 /* GetFeatureCount() */
436 /* */
437 /* If a spatial filter is in effect, we turn control over to */
438 /* the generic counter. Otherwise we return the total count. */
439 /* Eventually we should consider implementing a more efficient */
440 /* way of counting features matching a spatial query. */
441 /************************************************************************/
442
GetFeatureCount(int bForce)443 GIntBig OGRIDBTableLayer::GetFeatureCount( int bForce )
444
445 {
446 return OGRIDBLayer::GetFeatureCount( bForce );
447 }
448
449 /************************************************************************/
450 /* GetSpatialRef() */
451 /* */
452 /* We override this to try and fetch the table SRID from the */
453 /* geometry_columns table if the srsid is -2 (meaning we */
454 /* haven't yet even looked for it). */
455 /************************************************************************/
456
GetSpatialRef()457 OGRSpatialReference *OGRIDBTableLayer::GetSpatialRef()
458
459 {
460 if( nSRSId == -2 )
461 {
462 nSRSId = -1;
463
464 if ( ! pszGeomColumn )
465 return nullptr;
466
467 CPLString osCmd;
468 osCmd.Printf( " SELECT FIRST 1 srid, trim(srtext)"
469 " FROM spatial_ref_sys, %s"
470 " WHERE srid = ST_Srid(%s) ",
471 poFeatureDefn->GetName(), pszGeomColumn );
472
473 ITCursor oSridCur( *poDS->GetConnection() );
474
475 if( oSridCur.Prepare( osCmd.c_str() )&&
476 oSridCur.Open( ITCursor::ReadOnly ) )
477 {
478 ITRow * row = static_cast<ITRow *>( oSridCur.NextRow() );
479 if ( row && ! row->IsNull() )
480 {
481 nSRSId = atoi(row->Column(0)->Printable());
482 const char * wkt = row->Column(1)->Printable();
483
484 if ( poSRS )
485 {
486 // Hmm ... it should be null
487 delete poSRS;
488 }
489 poSRS = new OGRSpatialReference();
490 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
491 if ( poSRS->importFromWkt( wkt ) != OGRERR_NONE )
492 {
493 CPLError( CE_Warning, CPLE_AppDefined,
494 "Error parse srs wkt: %s", wkt );
495 delete poSRS;
496 poSRS = nullptr;
497 }
498 }
499 }
500 }
501
502 return OGRIDBLayer::GetSpatialRef();
503 }
504
505 #if 0
506 OGRErr OGRIDBTableLayer::ISetFeature( OGRFeature *poFeature )
507 {
508 OGRErr eErr(OGRERR_FAILURE);
509
510 if ( ! bUpdateAccess )
511 {
512 CPLError( CE_Failure, CPLE_AppDefined,
513 "Error update feature. Layer is read only." );
514 return eErr;
515 }
516
517 if( nullptr == poFeature )
518 {
519 CPLError( CE_Failure, CPLE_AppDefined,
520 "NULL pointer to OGRFeature passed to SetFeature()." );
521 return eErr;
522 }
523
524 if( poFeature->GetFID() == OGRNullFID )
525 {
526 CPLError( CE_Failure, CPLE_AppDefined,
527 "FID required on features given to SetFeature()." );
528 return eErr;
529 }
530
531 ITStatement oQuery( *poDS->GetConnection() );
532
533 int bUpdateGeom = TRUE;
534 OGRwkbGeometryType nGeomType = poFeature->GetGeometryRef()->getGeometryType();
535 CPLString osGeomFunc;
536 int nSrid = 0; // FIXME Obtain geometry SRID
537
538 switch (nGeomType)
539 {
540 case wkbPoint:
541 osGeomFunc = "ST_PointFromText";
542 break;
543 case wkbLineString:
544 osGeomFunc = "ST_LineFromText";
545 break;
546 case wkbPolygon:
547 osGeomFunc = "ST_PolyFromText";
548 break;
549 case wkbMultiPoint:
550 osGeomFunc = "ST_MPointFromText";
551 break;
552 case wkbMultiLineString:
553 osGeomFunc = "ST_MLineFromText";
554 break;
555 case wkbMultiPolygon:
556 osGeomFunc = "ST_MPolyFromText";
557 break;
558 default:
559 bUpdateGeom = FALSE;
560 CPLDebug("OGR_IDB", "SetFeature(): Unknown geometry type. Geometry will not be updated.");
561 }
562
563 // Create query
564 CPLString osSql;
565 CPLString osFields;
566
567 if ( pszGeomColumn && bUpdateGeom )
568 {
569 osFields.Printf( "%s = %s( ?, %d )", pszGeomColumn, osGeomFunc.c_str(), nSrid );
570 }
571
572 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
573 {
574 const char * pszFieldName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
575
576 // skip fid column from update
577 if ( EQUAL( pszFIDColumn, pszFieldName ) )
578 continue;
579
580 if ( ! osFields.empty() )
581 {
582 osFields += ",";
583 }
584
585 osFields += pszFieldName;
586 osFields += "=?";
587 }
588
589 osSql.Printf( "UPDATE %s SET %s WHERE %s = %d",
590 poFeatureDefn->GetName(),
591 osFields.c_str(),
592 pszFIDColumn,
593 poFeature->GetFID() );
594
595 if ( ! oQuery.Prepare( osSql.c_str() ) )
596 {
597 CPLError( CE_Failure, CPLE_AppDefined,
598 "Error prepare SQL.\n%s",osSql.c_str() );
599 return eErr;
600 }
601
602 int iParam = 0;
603
604 if ( pszGeomColumn && bUpdateGeom )
605 {
606 ITValue * par = oQuery.Param( iParam ); // it should be a geom value
607 if ( ! par )
608 {
609 CPLError( CE_Failure, CPLE_AppDefined,
610 "Error prepare geom param");
611 return eErr;
612 }
613
614 OGRGeometry * poGeom = poFeature->GetGeometryRef();
615 char * wkt;
616 poGeom->exportToWkt( &wkt );
617
618 if( ! par->FromPrintable( wkt ) )
619 {
620 CPLError( CE_Failure, CPLE_AppDefined,
621 "Error prepare geom param");
622 par->Release();
623 return eErr;
624 }
625
626 CPLFree( wkt );
627 par->Release();
628
629 iParam++;
630 }
631
632 for ( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
633 {
634 ITValue * par = oQuery.Param( iParam );
635 if ( ! par )
636 {
637 CPLError( CE_Failure, CPLE_AppDefined,
638 "Error prepare param %d", iParam);
639 return eErr;
640 }
641
642 if ( ! poFeature->IsFieldSetAndNotNull( i ) )
643 {
644 if ( ! par->SetNull() )
645 {
646 CPLError( CE_Failure, CPLE_AppDefined,
647 "Error set param %d to NULL", iParam);
648 par->Release();
649 return eErr;
650 }
651 par->Release();
652 continue;
653 }
654
655 ITConversions * cv = 0;
656 bool res = FALSE;
657
658 if ( par->QueryInterface( ITConversionsIID, (void **) &cv) !=
659 IT_QUERYINTERFACE_SUCCESS )
660 {
661 CPLError( CE_Failure, CPLE_AppDefined,
662 "Error prepare param %d", iParam);
663 par->Release();
664 return eErr;
665 }
666
667 switch ( poFeatureDefn->GetFieldDefn( i )->GetType() )
668 {
669 case OFTInteger:
670 res = cv->ConvertFrom( poFeature->GetFieldAsInteger( i ) );
671 break;
672
673 case OFTReal:
674 res = cv->ConvertFrom( poFeature->GetFieldAsDouble( i ) );
675 break;
676
677 case OFTIntegerList:
678 case OFTRealList:
679 case OFTStringList:
680 // FIXME Prepare array of values field
681 //cv->ConvertFrom( poFeature->GetFieldAsStringList( i ) );
682 //break;
683
684 case OFTBinary:
685 // FIXME Prepare binary field
686
687 case OFTString:
688 case OFTDate:
689 case OFTTime:
690 case OFTDateTime:
691 res = cv->ConvertFrom( poFeature->GetFieldAsString( i ) );
692 break;
693 default:
694 CPLError( CE_Failure, CPLE_AppDefined,
695 "Error prepare param %d. Unknown data type.", iParam);
696 cv->Release();
697 par->Release();
698 return eErr;
699 }
700 if ( res != TRUE )
701 CPLError( CE_Failure, CPLE_AppDefined,
702 "Error prepare param.");
703 cv->Release();
704 par->Release();
705 }
706
707 CPLDebug( "OGR_IDB", "ExecuteSQL(%s)", oQuery.QueryText().Data() );
708 if( !oQuery.Exec() )
709 {
710 CPLError( CE_Failure, CPLE_AppDefined, "Error update Feature.");
711 return eErr;
712 }
713
714 return OGRERR_NONE;
715 }
716
717 #endif
718
ISetFeature(OGRFeature * poFeature)719 OGRErr OGRIDBTableLayer::ISetFeature( OGRFeature *poFeature )
720 {
721 OGRErr eErr(OGRERR_FAILURE);
722
723 if ( ! bUpdateAccess )
724 {
725 CPLError( CE_Failure, CPLE_AppDefined,
726 "Error update feature. Layer is read only." );
727 return eErr;
728 }
729
730 if( nullptr == poFeature )
731 {
732 CPLError( CE_Failure, CPLE_AppDefined,
733 "NULL pointer to OGRFeature passed to SetFeature()." );
734 return eErr;
735 }
736
737 if( poFeature->GetFID() == OGRNullFID )
738 {
739 CPLError( CE_Failure, CPLE_AppDefined,
740 "FID required on features given to SetFeature()." );
741 return eErr;
742 }
743
744 ITStatement oQuery( *poDS->GetConnection() );
745
746 int bUpdateGeom = TRUE;
747 CPLString osGeomFunc;
748
749 if ( poFeature->GetGeometryRef() )
750 {
751 OGRwkbGeometryType nGeomType = poFeature->GetGeometryRef()->getGeometryType();
752
753 switch (nGeomType)
754 {
755 case wkbPoint:
756 osGeomFunc = "ST_PointFromText";
757 break;
758 case wkbLineString:
759 osGeomFunc = "ST_LineFromText";
760 break;
761 case wkbPolygon:
762 osGeomFunc = "ST_PolyFromText";
763 break;
764 case wkbMultiPoint:
765 osGeomFunc = "ST_MPointFromText";
766 break;
767 case wkbMultiLineString:
768 osGeomFunc = "ST_MLineFromText";
769 break;
770 case wkbMultiPolygon:
771 osGeomFunc = "ST_MPolyFromText";
772 break;
773 default:
774 bUpdateGeom = FALSE;
775 CPLDebug("OGR_IDB", "SetFeature(): Unknown geometry type. Geometry will not be updated.");
776 }
777 }
778 else
779 {
780 bUpdateGeom = FALSE;
781 }
782
783 // Create query
784 CPLString osSql;
785 CPLString osFields;
786
787 if ( pszGeomColumn && bUpdateGeom )
788 {
789 OGRGeometry * poGeom = poFeature->GetGeometryRef();
790 char * wkt;
791 poGeom->exportToWkt( &wkt );
792
793 osFields.Printf( "%s = %s( '%s', %d )", pszGeomColumn, osGeomFunc.c_str(), wkt, nSRSId );
794
795 CPLFree( wkt );
796 }
797
798 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
799 {
800 const char * pszFieldName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
801
802 // skip fid column from update
803 if ( EQUAL( pszFIDColumn, pszFieldName ) )
804 continue;
805
806 if ( ! osFields.empty() )
807 {
808 osFields += ",";
809 }
810
811 osFields += pszFieldName;
812 osFields += "=";
813
814 if ( ! poFeature->IsFieldSetAndNotNull( i ) )
815 {
816 osFields += "NULL";
817 continue;
818 }
819
820 CPLString osVal;
821
822 switch ( poFeatureDefn->GetFieldDefn( i )->GetType() )
823 {
824 case OFTInteger:
825 osVal.Printf( "%d", poFeature->GetFieldAsInteger( i ) );
826 break;
827
828 case OFTReal:
829 if ( poFeatureDefn->GetFieldDefn( i )->GetPrecision() )
830 {
831 // have a decimal format width.precision
832 CPLString osFormatString;
833 osFormatString.Printf( "%%%d.%df",
834 poFeatureDefn->GetFieldDefn( i )->GetWidth(),
835 poFeatureDefn->GetFieldDefn( i )->GetPrecision() );
836 osVal.Printf( osFormatString.c_str(), poFeature->GetFieldAsDouble( i ) );
837 }
838 else
839 osVal.Printf( "%f", poFeature->GetFieldAsDouble( i ) );
840 break;
841
842 case OFTIntegerList:
843 case OFTRealList:
844 case OFTStringList:
845 // FIXME Prepare array of values field
846 //cv->ConvertFrom( poFeature->GetFieldAsStringList( i ) );
847 //break;
848
849 case OFTBinary:
850 // FIXME Prepare binary field
851
852 case OFTString:
853 case OFTDate:
854 case OFTTime:
855 case OFTDateTime:
856 default:
857 osVal.Printf( "'%s'", poFeature->GetFieldAsString( i ) );
858 break;
859 }
860 osFields += osVal;
861 }
862
863 osSql.Printf( "UPDATE %s SET %s WHERE %s = " CPL_FRMT_GIB,
864 poFeatureDefn->GetName(),
865 osFields.c_str(),
866 pszFIDColumn,
867 poFeature->GetFID() );
868
869 if ( ! oQuery.Prepare( osSql.c_str() ) )
870 {
871 CPLError( CE_Failure, CPLE_AppDefined,
872 "Error prepare SQL.\n%s",osSql.c_str() );
873 return eErr;
874 }
875
876 CPLDebug( "OGR_IDB", "Exec(%s)", oQuery.QueryText().Data() );
877 if( !oQuery.Exec() )
878 {
879 CPLError( CE_Failure, CPLE_AppDefined, "Error update Feature.");
880 return eErr;
881 }
882
883 return OGRERR_NONE;
884 }
885
ICreateFeature(OGRFeature * poFeature)886 OGRErr OGRIDBTableLayer::ICreateFeature( OGRFeature *poFeature )
887 {
888 OGRErr eErr(OGRERR_FAILURE);
889
890 if ( ! bUpdateAccess )
891 {
892 CPLError( CE_Failure, CPLE_AppDefined,
893 "Error create feature. Layer is read only." );
894 return eErr;
895 }
896
897 if( nullptr == poFeature )
898 {
899 CPLError( CE_Failure, CPLE_AppDefined,
900 "NULL pointer to OGRFeature passed to CreateFeature()." );
901 return eErr;
902 }
903
904 if( poFeature->GetFID() != OGRNullFID && pszFIDColumn== nullptr )
905 {
906 CPLError( CE_Failure, CPLE_AppDefined,
907 "FID ignored on feature given to CreateFeature(). Unknown FID column." );
908 return eErr;
909 }
910
911 int bUpdateGeom = TRUE;
912 CPLString osGeomFunc;
913
914 if ( poFeature->GetGeometryRef() )
915 {
916 OGRwkbGeometryType nGeomType = poFeature->GetGeometryRef()->getGeometryType();
917
918 switch (nGeomType)
919 {
920 case wkbPoint:
921 osGeomFunc = "ST_PointFromText";
922 break;
923 case wkbLineString:
924 osGeomFunc = "ST_LineFromText";
925 break;
926 case wkbPolygon:
927 osGeomFunc = "ST_PolyFromText";
928 break;
929 case wkbMultiPoint:
930 osGeomFunc = "ST_MPointFromText";
931 break;
932 case wkbMultiLineString:
933 osGeomFunc = "ST_MLineFromText";
934 break;
935 case wkbMultiPolygon:
936 osGeomFunc = "ST_MPolyFromText";
937 break;
938 default:
939 bUpdateGeom = FALSE;
940 CPLDebug("OGR_IDB", "SetFeature(): Unknown geometry type. Geometry will not be updated.");
941 }
942 }
943 else
944 bUpdateGeom = FALSE;
945
946 // Create query
947 CPLString osSql;
948 CPLString osFields;
949 CPLString osValues;
950
951 if ( pszGeomColumn && bUpdateGeom )
952 {
953 OGRGeometry * poGeom = poFeature->GetGeometryRef();
954 char * wkt;
955 poGeom->exportToWkt( &wkt );
956
957 osFields += pszGeomColumn;
958 osValues.Printf( "%s( '%s', %d )", osGeomFunc.c_str(), wkt, nSRSId );
959
960 CPLFree( wkt );
961 }
962
963 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
964 {
965 const char * pszFieldName = poFeatureDefn->GetFieldDefn(i)->GetNameRef();
966
967 // Skip NULL fields
968 if ( ! poFeature->IsFieldSetAndNotNull( i ) )
969 {
970 continue;
971 }
972
973 if ( ! osFields.empty() )
974 {
975 osFields += ",";
976 osValues += ",";
977 }
978
979 osFields += pszFieldName;
980
981 CPLString osVal;
982
983 switch ( poFeatureDefn->GetFieldDefn( i )->GetType() )
984 {
985 case OFTInteger:
986 osVal.Printf( "%d", poFeature->GetFieldAsInteger( i ) );
987 break;
988
989 case OFTReal:
990 if ( poFeatureDefn->GetFieldDefn( i )->GetPrecision() )
991 {
992 // have a decimal format width.precision
993 CPLString osFormatString;
994 osFormatString.Printf( "%%%d.%df",
995 poFeatureDefn->GetFieldDefn( i )->GetWidth(),
996 poFeatureDefn->GetFieldDefn( i )->GetPrecision() );
997 osVal.Printf( osFormatString.c_str(), poFeature->GetFieldAsDouble( i ) );
998 }
999 else
1000 osVal.Printf( "%f", poFeature->GetFieldAsDouble( i ) );
1001 break;
1002
1003 case OFTIntegerList:
1004 case OFTRealList:
1005 case OFTStringList:
1006 // FIXME Prepare array of values field
1007 //cv->ConvertFrom( poFeature->GetFieldAsStringList( i ) );
1008 //break;
1009
1010 case OFTBinary:
1011 // FIXME Prepare binary field
1012
1013 case OFTString:
1014 case OFTDate:
1015 case OFTTime:
1016 case OFTDateTime:
1017 default:
1018 osVal.Printf( "'%s'", poFeature->GetFieldAsString( i ) );
1019 break;
1020 }
1021 osValues += osVal;
1022 }
1023
1024 osSql.Printf( "INSERT INTO %s (%s) VALUES (%s)",
1025 poFeatureDefn->GetName(),
1026 osFields.c_str(),
1027 osValues.c_str() );
1028
1029 ITStatement oQuery( *poDS->GetConnection() );
1030
1031 if ( ! oQuery.Prepare( osSql.c_str() ) )
1032 {
1033 CPLError( CE_Failure, CPLE_AppDefined,
1034 "Error prepare SQL.\n%s",osSql.c_str() );
1035 return eErr;
1036 }
1037
1038 CPLDebug( "OGR_IDB", "Exec(%s)", oQuery.QueryText().Data() );
1039 if( !oQuery.Exec() )
1040 {
1041 CPLError( CE_Failure, CPLE_AppDefined, "Error create Feature.");
1042 return eErr;
1043 }
1044
1045 ITQuery oFidQuery( *poDS->GetConnection() );
1046 osSql.Printf( "SELECT MAX(%s) from %s", pszFIDColumn, poFeatureDefn->GetName() );
1047
1048 CPLDebug( "OGR_IDB", "Exec(%s)", osSql.c_str() );
1049
1050 ITRow * row = oFidQuery.ExecOneRow( osSql.c_str() );
1051 if( ! row || row->NumColumns() < 1 )
1052 {
1053 CPLError( CE_Failure, CPLE_AppDefined, "Error create Feature.");
1054 return eErr;
1055 }
1056
1057 int fid = atoi( row->Column(0)->Printable() );
1058
1059 if ( fid > 0 )
1060 poFeature->SetFID( fid );
1061 else
1062 {
1063 CPLError( CE_Failure, CPLE_AppDefined, "Error create Feature. Unable to get new fid" );
1064 return eErr;
1065 }
1066
1067 return OGRERR_NONE;
1068 }
1069