1 /*****************************************************************************
2 *
3 * Project: DB2 Spatial driver
4 * Purpose: Implements OGRDB2TableLayer class, access to an existing table.
5 * Author: David Adler, dadler at adtechgeospatial dot com
6 *
7 *****************************************************************************
8 * Copyright (c) 2010, Tamas Szekeres
9 * Copyright (c) 2015, David Adler
10 * Permission is hereby granted, free of charge, to any person obtaining a
11 * copy of this software and associated documentation files (the "Software"),
12 * to deal in the Software without restriction, including without limitation
13 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 * and/or sell copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included
18 * in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ****************************************************************************/
28
29 #include "cpl_conv.h"
30 #include "ogr_db2.h"
31
32 CPL_CVSID("$Id: ogrdb2tablelayer.cpp 8c3e4ef55212f20eec95aa7e12ba5d48dacfdc47 2020-10-01 21:20:51 +0200 Even Rouault $")
33
34 /************************************************************************/
35 /* OGRDB2AppendEscaped( ) */
36 /************************************************************************/
37
OGRDB2AppendEscaped(OGRDB2Statement * poStatement,const char * pszStrValue)38 void OGRDB2AppendEscaped( OGRDB2Statement* poStatement,
39 const char* pszStrValue)
40 {
41 if (!pszStrValue)
42 {
43 poStatement->Append("null");
44 return;
45 }
46
47 size_t iIn, iOut , nTextLen = strlen(pszStrValue);
48 char *pszEscapedText = (char *) VSIMalloc(nTextLen*2 + 3);
49
50 pszEscapedText[0] = '\'';
51
52 for( iIn = 0, iOut = 1; iIn < nTextLen; iIn++ )
53 {
54 switch( pszStrValue[iIn] )
55 {
56 case '\'':
57 pszEscapedText[iOut++] = '\''; // double quote
58 pszEscapedText[iOut++] = pszStrValue[iIn];
59 break;
60
61 default:
62 pszEscapedText[iOut++] = pszStrValue[iIn];
63 break;
64 }
65 }
66
67 pszEscapedText[iOut++] = '\'';
68
69 pszEscapedText[iOut] = '\0';
70
71 poStatement->Append(pszEscapedText);
72
73 CPLFree( pszEscapedText );
74 }
75
76 /************************************************************************/
77 /* OGRDB2TableLayer() */
78 /************************************************************************/
79
OGRDB2TableLayer(OGRDB2DataSource * poDSIn)80 OGRDB2TableLayer::OGRDB2TableLayer( OGRDB2DataSource *poDSIn ) :
81 eGeomType( wkbNone )
82
83 {
84 poDS = poDSIn;
85 m_poStmt = nullptr;
86 m_poPrepStmt = nullptr;
87 m_pszQuery = nullptr;
88 m_nFeaturesRead = 0;
89
90 bUpdateAccess = TRUE;
91
92 iNextShapeId = 0;
93
94 nSRSId = -1;
95
96 poFeatureDefn = nullptr;
97
98 pszTableName = nullptr;
99 m_pszLayerName = nullptr;
100 pszSchemaName = nullptr;
101 pszFIDColumn = nullptr;
102
103 bLaunderColumnNames = false;
104 bPreservePrecision = false;
105 bNeedSpatialIndex = false;
106 m_iSrs = 0;
107 }
108
109 /************************************************************************/
110 /* ~OGRDB2TableLayer() */
111 /************************************************************************/
112
~OGRDB2TableLayer()113 OGRDB2TableLayer::~OGRDB2TableLayer()
114
115 {
116 CPLDebug("OGRDB2TableLayer::~OGRDB2TableLayer","entering");
117 CPLFree( pszTableName );
118 CPLFree( m_pszLayerName );
119 CPLFree( pszSchemaName );
120
121 CPLFree( m_pszQuery );
122 ClearStatement();
123 if( m_poPrepStmt != nullptr )
124 {
125 delete m_poPrepStmt;
126 m_poPrepStmt = nullptr;
127 }
128 CPLDebug("OGRDB2TableLayer::~OGRDB2TableLayer","exiting");
129 }
130
131 /************************************************************************/
132 /* GetName() */
133 /************************************************************************/
134
GetName()135 const char *OGRDB2TableLayer::GetName()
136
137 {
138 return m_pszLayerName;
139 }
140
141 /************************************************************************/
142 /* GetLayerDefn() */
143 /************************************************************************/
GetLayerDefn()144 OGRFeatureDefn* OGRDB2TableLayer::GetLayerDefn()
145 {
146 if (poFeatureDefn)
147 return poFeatureDefn;
148
149 OGRDB2Session *poSession = poDS->GetSession();
150 /* -------------------------------------------------------------------- */
151 /* Do we have a simple primary key? */
152 /* -------------------------------------------------------------------- */
153 OGRDB2Statement oGetKey( poSession );
154 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
155 "pszTableName: %s; pszSchemaName: %s",
156 pszTableName, pszSchemaName);
157 if( oGetKey.GetPrimaryKeys( pszTableName, nullptr, pszSchemaName ) ) {
158 if( oGetKey.Fetch() )
159 {
160 pszFIDColumn = CPLStrdup(oGetKey.GetColData( 3 ));
161 if( oGetKey.Fetch() ) // more than one field in key!
162 {
163 oGetKey.Clear();
164 CPLFree( pszFIDColumn );
165 pszFIDColumn = nullptr;
166 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
167 "Table %s has multiple primary key fields, "
168 "ignoring them all.", pszTableName );
169 } else {
170 // Attempt to get the 'identity' and 'generated' information
171 // from syscat.columns. This is only valid on DB2 LUW so if it
172 // fails, we assume that we are running on z/OS.
173 OGRDB2Statement oStatement = OGRDB2Statement(
174 poDS->GetSession());
175 oStatement.Appendf( "select identity, generated "
176 "from syscat.columns "
177 "where tabschema = '%s' "
178 "and tabname = '%s' and colname = '%s'",
179 pszSchemaName, pszTableName,
180 pszFIDColumn );
181
182 if( oStatement.DB2Execute("OGR_DB2TableLayer::GetLayerDefn") )
183 {
184 if( oStatement.Fetch() )
185 {
186 if ( oStatement.GetColData( 0 )
187 && EQUAL(oStatement.GetColData( 0 ), "Y")) {
188 bIsIdentityFid = TRUE;
189 if ( oStatement.GetColData( 1 ) ) {
190 cGenerated = oStatement.GetColData( 1 )[0];
191 }
192 }
193 }
194 } else {
195 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
196 "Must be z/OS");
197 // on z/OS, get all the column data for table and loop
198 // through looking for the FID column, then check the
199 // column default information for 'IDENTIY' and 'ALWAYS'
200 if (oGetKey.GetColumns(pszTableName, nullptr, pszSchemaName))
201 {
202 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
203 "GetColumns succeeded");
204 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
205 "ColName[0]: '%s'",oGetKey.GetColName(0));
206 for (int idx = 0; idx < oGetKey.GetColCount(); idx++)
207 {
208 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
209 "ColName[0]: '%s'",
210 oGetKey.GetColName(idx));
211 if (!strcmp(pszFIDColumn,oGetKey.GetColName(idx)))
212 {
213 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
214 "ColDef[0]: '%s'",
215 oGetKey.GetColColumnDef(idx));
216 if (strstr(oGetKey.GetColColumnDef(idx),
217 "IDENTITY"))
218 bIsIdentityFid = TRUE;
219 if (strstr(oGetKey.GetColColumnDef(idx),
220 "ALWAYS"))
221 cGenerated = 'A';
222 }
223 }
224 }
225 }
226 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn",
227 "FIDColumn: '%s', identity: '%d', generated: '%c'",
228 pszFIDColumn, bIsIdentityFid, cGenerated);
229 }
230 }
231 } else
232 CPLDebug( "OGR_DB2TableLayer::GetLayerDefn", "GetPrimaryKeys failed");
233
234 /* -------------------------------------------------------------------- */
235 /* Get the column definitions for this table. */
236 /* -------------------------------------------------------------------- */
237 OGRDB2Statement oGetCol( poSession );
238 CPLErr eErr;
239
240 if( !oGetCol.GetColumns( pszTableName, "", pszSchemaName ) )
241 return nullptr;
242
243 eErr = BuildFeatureDefn( m_pszLayerName, &oGetCol );
244 if( eErr != CE_None )
245 return nullptr;
246
247 if (eGeomType != wkbNone)
248 poFeatureDefn->SetGeomType(eGeomType);
249
250 if ( GetSpatialRef() && poFeatureDefn->GetGeomFieldCount() == 1)
251 poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef( poSRS );
252
253 if( poFeatureDefn->GetFieldCount() == 0 &&
254 pszFIDColumn == nullptr && pszGeomColumn == nullptr )
255 {
256 CPLError( CE_Failure, CPLE_AppDefined,
257 "No column definitions found for table '%s', "
258 "layer not usable.",
259 m_pszLayerName );
260 return nullptr;
261 }
262
263 /* -------------------------------------------------------------------- */
264 /* If we got a geometry column, does it exist? Is it binary? */
265 /* -------------------------------------------------------------------- */
266
267 if( pszGeomColumn != nullptr )
268 {
269 poFeatureDefn->GetGeomFieldDefn(0)->SetName( pszGeomColumn );
270 int iColumn = oGetCol.GetColId( pszGeomColumn );
271 if( iColumn < 0 )
272 {
273 CPLError( CE_Failure, CPLE_AppDefined,
274 "Column %s requested for geometry, "
275 "but it does not exist.",
276 pszGeomColumn );
277 CPLFree( pszGeomColumn );
278 pszGeomColumn = nullptr;
279 }
280 }
281
282 return poFeatureDefn;
283 }
284
285 /************************************************************************/
286 /* Initialize() */
287 /************************************************************************/
288
Initialize(const char * pszSchema,const char * pszLayerName,const char * pszGeomCol,CPL_UNUSED int nCoordDimension,int nSRId,const char * pszSRText,OGRwkbGeometryType eType)289 CPLErr OGRDB2TableLayer::Initialize( const char *pszSchema,
290 const char *pszLayerName,
291 const char *pszGeomCol,
292 CPL_UNUSED int nCoordDimension,
293 int nSRId,
294 const char *pszSRText,
295 OGRwkbGeometryType eType )
296 {
297 // CPLFree( pszFIDColumn );
298 pszFIDColumn = nullptr;
299
300 CPLDebug( "OGR_DB2TableLayer::Initialize",
301 "schema: '%s', layerName: '%s', geomCol: '%s'",
302 pszSchema, pszLayerName, pszGeomCol);
303 CPLDebug( "OGR_DB2TableLayer::Initialize",
304 "nSRId: '%d', eType: '%d', srText: '%s'",
305 nSRId, eType, pszSRText);
306
307 /* -------------------------------------------------------------------- */
308 /* Parse out schema name if present in layer. We assume a */
309 /* schema is provided if there is a dot in the name, and that */
310 /* it is in the form <schema>.<tablename> */
311 /* -------------------------------------------------------------------- */
312 const char *pszDot = strstr(pszLayerName,".");
313 if( pszDot != nullptr )
314 {
315 pszTableName = CPLStrdup(pszDot + 1);
316 pszSchemaName = CPLStrdup(pszLayerName);
317 pszSchemaName[pszDot - pszLayerName] = '\0';
318 this->m_pszLayerName = CPLStrdup(pszLayerName);
319 }
320 else
321 {
322 pszTableName = CPLStrdup(pszLayerName);
323 pszSchemaName = CPLStrdup(pszSchema);
324 this->m_pszLayerName = CPLStrdup(CPLSPrintf("%s.%s", pszSchemaName,
325 pszTableName));
326 }
327 SetDescription( this->m_pszLayerName );
328 CPLDebug( "OGR_DB2TableLayer::Initialize",
329 "this->m_pszLayerName: '%s', layerName: '%s', geomCol: '%s'",
330 this->m_pszLayerName, pszLayerName, pszGeomCol);
331 /* -------------------------------------------------------------------- */
332 /* Have we been provided a geometry column? */
333 /* -------------------------------------------------------------------- */
334 // CPLFree( pszGeomColumn ); LATER
335 if( pszGeomCol == nullptr )
336 GetLayerDefn(); /* fetch geom column if not specified */
337 else
338 pszGeomColumn = CPLStrdup( pszGeomCol );
339
340 if (eType != wkbNone)
341 eGeomType = eType;
342
343 /* -------------------------------------------------------------------- */
344 /* Try to find out the spatial reference */
345 /* -------------------------------------------------------------------- */
346
347 nSRSId = nSRId;
348
349 if (pszSRText)
350 {
351 /* Process srtext directly if specified */
352 poSRS = new OGRSpatialReference();
353 poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
354 if( poSRS->importFromWkt( (char**)&pszSRText ) != OGRERR_NONE )
355 {
356 delete poSRS;
357 poSRS = nullptr;
358 }
359 }
360
361 if (!poSRS)
362 {
363 if (nSRSId < 0)
364 nSRSId = FetchSRSId();
365
366 GetSpatialRef();
367 }
368
369 return CE_None;
370 }
371
372 /************************************************************************/
373 /* FetchSRSId() */
374 /************************************************************************/
375
FetchSRSId()376 int OGRDB2TableLayer::FetchSRSId()
377 {
378 OGRDB2Statement oStatement = OGRDB2Statement( poDS->GetSession() );
379
380 // first try to get the srid from st_geometry_columns
381 // if the spatial column was registered
382 oStatement.Appendf( "select srs_id from db2gse.st_geometry_columns "
383 "where table_schema = '%s' and table_name = '%s'",
384 pszSchemaName, pszTableName );
385
386 if( oStatement.DB2Execute("OGRDB2TableLayer::FetchSRSId")
387 && oStatement.Fetch() )
388 {
389 if ( oStatement.GetColData( 0 ) )
390 nSRSId = atoi( oStatement.GetColData( 0 ) );
391 }
392
393 // If it was not found there, try to get it from the data table.
394 // This only works if there is spatial data in the first row.
395 if (nSRSId < 0 )
396 {
397 oStatement.Clear();
398 oStatement.Appendf("select db2gse.st_srid(%s) from %s.%s "
399 "fetch first row only",
400 pszGeomColumn, pszSchemaName, pszTableName);
401 if ( oStatement.DB2Execute("OGR_DB2TableLayer::FetchSRSId")
402 && oStatement.Fetch() )
403 {
404 if ( oStatement.GetColData( 0 ) )
405 nSRSId = atoi( oStatement.GetColData( 0 ) );
406 }
407 }
408 CPLDebug( "OGR_DB2TableLayer::FetchSRSId", "nSRSId: '%d'",
409 nSRSId);
410 return nSRSId;
411 }
412
413 /************************************************************************/
414 /* CreateSpatialIndex() */
415 /* */
416 /* Create a spatial index on the geometry column of the layer */
417 /************************************************************************/
418
CreateSpatialIndex()419 OGRErr OGRDB2TableLayer::CreateSpatialIndex()
420 {
421 CPLDebug("OGRDB2TableLayer::CreateSpatialIndex","Enter");
422 if (poDS->m_bIsZ) {
423 CPLDebug("OGRDB2TableLayer::CreateSpatialIndex",
424 "Don't create spatial index on z/OS");
425 return OGRERR_NONE;
426 }
427 GetLayerDefn();
428
429 OGRDB2Statement oStatement( poDS->GetSession() );
430
431 OGREnvelope oExt;
432 if (GetExtent(&oExt, TRUE) != OGRERR_NONE)
433 {
434 CPLError( CE_Failure, CPLE_AppDefined,
435 "Failed to get extent for spatial index." );
436 return OGRERR_FAILURE;
437 }
438 CPLDebug("OGRDB2TableLayer::CreateSpatialIndex",
439 "BOUNDING_BOX =(%.15g, %.15g, %.15g, %.15g)",
440 oExt.MinX, oExt.MinY, oExt.MaxX, oExt.MaxY );
441
442 oStatement.Appendf("CREATE INDEX %s.%s_sidx ON %s.%s ( %s ) "
443 "extend using db2gse.spatial_index(.1,0.5,0)",
444 pszSchemaName, pszTableName,
445 pszSchemaName, pszTableName, pszGeomColumn );
446
447 if( !oStatement.DB2Execute("OGR_DB2TableLayer::CreateSpatialIndex") )
448 {
449 CPLError( CE_Failure, CPLE_AppDefined,
450 "Failed to create the spatial index, %s.",
451 poDS->GetSession()->GetLastError());
452 return OGRERR_FAILURE;
453 }
454
455 return OGRERR_NONE;
456 }
457
458 /************************************************************************/
459 /* DropSpatialIndex() */
460 /* */
461 /* Drop the spatial index on the geometry column of the layer */
462 /************************************************************************/
463
DropSpatialIndex()464 void OGRDB2TableLayer::DropSpatialIndex()
465 {
466 GetLayerDefn();
467
468 OGRDB2Statement oStatement( poDS->GetSession() );
469
470 oStatement.Appendf("DROP INDEX %s.%s",
471 pszSchemaName, pszTableName);
472
473 //poDS->GetSession()->BeginTransaction();
474
475 if( !oStatement.DB2Execute("OGR_DB2TableLayer::DropSpatialIndex") )
476 {
477 CPLError( CE_Failure, CPLE_AppDefined,
478 "Failed to drop the spatial index, %s.",
479 poDS->GetSession()->GetLastError());
480 return;
481 }
482
483 //poDS->GetSession()->CommitTransaction();
484 }
485
486 /************************************************************************/
487 /* BuildFields() */
488 /* */
489 /* Build list of fields to fetch, performing any required */
490 /* transformations (such as on geometry). */
491 /************************************************************************/
492
BuildFields()493 CPLString OGRDB2TableLayer::BuildFields()
494
495 {
496 int nColumn = 0;
497 CPLString osFieldList;
498
499 GetLayerDefn();
500
501 if( pszFIDColumn && poFeatureDefn->GetFieldIndex( pszFIDColumn ) == -1 )
502 {
503 /* Always get the FID column */
504 osFieldList += " ";
505 osFieldList += pszFIDColumn;
506 osFieldList += " ";
507 ++nColumn;
508 }
509
510 if( pszGeomColumn && !poFeatureDefn->IsGeometryIgnored())
511 {
512 if( nColumn > 0 )
513 osFieldList += ", ";
514
515 osFieldList += " db2gse.st_astext(";
516 osFieldList += pszGeomColumn;
517 osFieldList += ") as ";
518 osFieldList += pszGeomColumn;
519
520 osFieldList += " ";
521
522 ++nColumn;
523 }
524
525 if (poFeatureDefn->GetFieldCount() > 0)
526 {
527 /* need to reconstruct the field ordinals list */
528 CPLFree(panFieldOrdinals);
529 panFieldOrdinals = (int *) CPLMalloc( sizeof(int)
530 * poFeatureDefn->GetFieldCount() );
531
532 for( int i = 0; i < poFeatureDefn->GetFieldCount(); i++ )
533 {
534 if ( poFeatureDefn->GetFieldDefn(i)->IsIgnored() )
535 continue;
536
537 const char *pszName =poFeatureDefn->GetFieldDefn(i)->GetNameRef();
538
539 if( nColumn > 0 )
540 osFieldList += ", ";
541
542 osFieldList += " ";
543 osFieldList += pszName;
544 osFieldList += " ";
545
546 panFieldOrdinals[i] = nColumn;
547
548 ++nColumn;
549 }
550 }
551
552 return osFieldList;
553 }
554
555 /************************************************************************/
556 /* ClearStatement() */
557 /************************************************************************/
558
ClearStatement()559 void OGRDB2TableLayer::ClearStatement()
560
561 {
562 if( m_poStmt != nullptr )
563 {
564 delete m_poStmt;
565 m_poStmt = nullptr;
566 }
567 }
568
569 /************************************************************************/
570 /* GetStatement() */
571 /************************************************************************/
572
GetStatement()573 OGRDB2Statement *OGRDB2TableLayer::GetStatement()
574
575 {
576 if( m_poStmt == nullptr )
577 {
578 m_poStmt = BuildStatement(BuildFields());
579 iNextShapeId = 0;
580 }
581
582 return m_poStmt;
583 }
584
585 /************************************************************************/
586 /* BuildStatement() */
587 /************************************************************************/
588
BuildStatement(const char * pszColumns)589 OGRDB2Statement* OGRDB2TableLayer::BuildStatement(const char* pszColumns)
590
591 {
592 OGRDB2Statement* poStatement = new OGRDB2Statement( poDS->GetSession());
593 poStatement->Append( "select " );
594 poStatement->Append( pszColumns );
595 poStatement->Append( " from " );
596 poStatement->Append( pszSchemaName );
597 poStatement->Append( "." );
598 poStatement->Append( pszTableName );
599
600 /* Append attribute query if we have it */
601 if( m_pszQuery != nullptr )
602 poStatement->Appendf( " where (%s)", m_pszQuery );
603
604 /* If we have a spatial filter, query on it */
605 if ( m_poFilterGeom != nullptr )
606 {
607 if( m_pszQuery == nullptr )
608 poStatement->Append( " where" );
609 else
610 poStatement->Append( " and" );
611
612 poStatement->Appendf(" db2gse.envelopesintersect(%s,%.15g,%.15g,"
613 "%.15g,%.15g, 0) = 1",
614 pszGeomColumn, m_sFilterEnvelope.MinX,
615 m_sFilterEnvelope.MinY, m_sFilterEnvelope.MaxX,
616 m_sFilterEnvelope.MaxY );
617 }
618
619 if( poStatement->DB2Execute("OGR_DB2TableLayer::BuildStatement") ) {
620 return poStatement;
621 }
622 else
623 {
624 delete poStatement;
625 CPLDebug( "OGR_DB2TableLayer::BuildStatement", "ExecuteSQL Failed" );
626 return nullptr;
627 }
628 }
629
630 /************************************************************************/
631 /* ResetReading() */
632 /************************************************************************/
633
ResetReading()634 void OGRDB2TableLayer::ResetReading()
635
636 {
637 ClearStatement();
638 OGRDB2Layer::ResetReading();
639 }
640
641 /************************************************************************/
642 /* GetFeature() */
643 /************************************************************************/
644
GetFeature(GIntBig nFeatureId)645 OGRFeature *OGRDB2TableLayer::GetFeature( GIntBig nFeatureId )
646
647 {
648
649 if( pszFIDColumn == nullptr )
650 return OGRDB2Layer::GetFeature( nFeatureId );
651
652 ClearStatement();
653
654 iNextShapeId = nFeatureId;
655
656 m_poStmt = new OGRDB2Statement( poDS->GetSession() );
657 CPLString osFields = BuildFields();
658 m_poStmt->Appendf( "select %s from %s where %s = " CPL_FRMT_GIB, osFields.c_str(),
659 poFeatureDefn->GetName(), pszFIDColumn, nFeatureId );
660
661 if( !m_poStmt->DB2Execute("OGR_DB2TableLayer::GetFeature") )
662 {
663 delete m_poStmt;
664 m_poStmt = nullptr;
665 return nullptr;
666 }
667
668 return GetNextRawFeature();
669 }
670
671 /************************************************************************/
672 /* SetAttributeFilter() */
673 /************************************************************************/
674
SetAttributeFilter(const char * pszQuery)675 OGRErr OGRDB2TableLayer::SetAttributeFilter( const char *pszQuery )
676
677 {
678 CPLFree(m_pszAttrQueryString);
679 m_pszAttrQueryString = (pszQuery) ? CPLStrdup(pszQuery) : nullptr;
680
681 if( (pszQuery == nullptr && this->m_pszQuery == nullptr)
682 || (pszQuery != nullptr && this->m_pszQuery != nullptr
683 && EQUAL(pszQuery,this->m_pszQuery)) )
684 return OGRERR_NONE;
685
686 CPLFree( this->m_pszQuery );
687 this->m_pszQuery = (pszQuery) ? CPLStrdup( pszQuery ) : nullptr;
688
689 ClearStatement();
690
691 return OGRERR_NONE;
692 }
693
694 /************************************************************************/
695 /* TestCapability() */
696 /************************************************************************/
697
TestCapability(const char * pszCap)698 int OGRDB2TableLayer::TestCapability( const char * pszCap )
699
700 {
701 if ( bUpdateAccess )
702 {
703 if( EQUAL(pszCap,OLCSequentialWrite) || EQUAL(pszCap,OLCCreateField)
704 || EQUAL(pszCap,OLCDeleteFeature) )
705 return TRUE;
706
707 else if( EQUAL(pszCap,OLCRandomWrite) )
708 return pszFIDColumn != nullptr;
709 }
710
711 if( EQUAL(pszCap,OLCTransactions) )
712 return TRUE;
713
714 if( EQUAL(pszCap,OLCIgnoreFields) )
715 return TRUE;
716
717 if( EQUAL(pszCap,OLCRandomRead) )
718 return pszFIDColumn != nullptr;
719 else if( EQUAL(pszCap,OLCFastFeatureCount) )
720 return TRUE;
721 else
722 return OGRDB2Layer::TestCapability( pszCap );
723 }
724
725 /************************************************************************/
726 /* GetFeatureCount() */
727 /************************************************************************/
728
GetFeatureCount(int bForce)729 GIntBig OGRDB2TableLayer::GetFeatureCount( int bForce )
730
731 {
732 GetLayerDefn();
733
734 if( TestCapability(OLCFastFeatureCount) == FALSE )
735 return OGRDB2Layer::GetFeatureCount( bForce );
736
737 ClearStatement();
738
739 OGRDB2Statement* poStatement = BuildStatement( "count(*)" );
740
741 if (poStatement == nullptr || !poStatement->Fetch())
742 {
743 delete poStatement;
744 return OGRDB2Layer::GetFeatureCount( bForce );
745 }
746
747 int nRet = atoi(poStatement->GetColData( 0 ));
748 delete poStatement;
749 return nRet;
750 }
751
752 /************************************************************************/
753 /* CreateField() */
754 /************************************************************************/
755
CreateField(OGRFieldDefn * poFieldIn,int bApproxOK)756 OGRErr OGRDB2TableLayer::CreateField( OGRFieldDefn *poFieldIn,
757 int bApproxOK )
758
759 {
760 char szFieldType[256];
761 OGRFieldDefn oField( poFieldIn );
762
763 GetLayerDefn();
764
765 /* -------------------------------------------------------------------- */
766 /* Do we want to "launder" the column names into DB2 */
767 /* friendly format? */
768 /* -------------------------------------------------------------------- */
769 if( bLaunderColumnNames )
770 {
771 char *pszSafeName = poDS->LaunderName( oField.GetNameRef() );
772
773 oField.SetName( pszSafeName );
774 CPLFree( pszSafeName );
775 }
776
777 /* -------------------------------------------------------------------- */
778 /* Identify the DB2 type. */
779 /* -------------------------------------------------------------------- */
780
781 int fieldType = oField.GetType();
782 CPLDebug("OGR_DB2TableLayer::CreateField","fieldType: %d", fieldType);
783 if( oField.GetType() == OFTInteger )
784 {
785 if( oField.GetWidth() > 0 && bPreservePrecision )
786 snprintf( szFieldType, sizeof(szFieldType), "numeric(%d,0)", oField.GetWidth() );
787 else
788 strcpy( szFieldType, "int" );
789 }
790 else if( oField.GetType() == OFTInteger64 )
791 {
792 if( oField.GetWidth() > 0 && bPreservePrecision )
793 snprintf( szFieldType, sizeof(szFieldType), "numeric(%d,0)", oField.GetWidth() );
794 else
795 strcpy( szFieldType, "bigint" );
796 }
797 else if( oField.GetType() == OFTReal )
798 {
799 if( oField.GetWidth() > 0 && oField.GetPrecision() > 0
800 && bPreservePrecision )
801 snprintf( szFieldType, sizeof(szFieldType), "numeric(%d,%d)",
802 oField.GetWidth(), oField.GetPrecision() );
803 else
804 strcpy( szFieldType, "float" );
805 }
806 else if( oField.GetType() == OFTString )
807 {
808 if( oField.GetWidth() == 0 || !bPreservePrecision )
809 strcpy( szFieldType, "varchar(MAX)" );
810 else
811 snprintf( szFieldType, sizeof(szFieldType), "varchar(%d)", oField.GetWidth() );
812 }
813 else if( oField.GetType() == OFTDate )
814 {
815 strcpy( szFieldType, "date" );
816 }
817 else if( oField.GetType() == OFTTime )
818 {
819 strcpy( szFieldType, "time(7)" );
820 }
821 else if( oField.GetType() == OFTDateTime )
822 {
823 strcpy( szFieldType, "datetime" );
824 }
825 else if( oField.GetType() == OFTBinary )
826 {
827 strcpy( szFieldType, "image" );
828 }
829 else if( bApproxOK )
830 {
831 CPLError( CE_Warning, CPLE_NotSupported,
832 "Can't create field %s with type %s on DB2 layers. "
833 "Creating as varchar.",
834 oField.GetNameRef(),
835 OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
836 strcpy( szFieldType, "varchar" );
837 }
838 else
839 {
840 CPLError( CE_Failure, CPLE_NotSupported,
841 "Can't create field %s with type %s on DB2 layers.",
842 oField.GetNameRef(),
843 OGRFieldDefn::GetFieldTypeName(oField.GetType()) );
844
845 return OGRERR_FAILURE;
846 }
847
848 /* -------------------------------------------------------------------- */
849 /* Create the new field. */
850 /* -------------------------------------------------------------------- */
851
852 OGRDB2Statement oStmt( poDS->GetSession() );
853
854 oStmt.Appendf( "ALTER TABLE %s.%s ADD COLUMN %s %s",
855 pszSchemaName, pszTableName, oField.GetNameRef(),
856 szFieldType);
857
858 if( !oStmt.DB2Execute("OGR_DB2TableLayer::CreateField") )
859 {
860 CPLError( CE_Failure, CPLE_AppDefined,
861 "Error creating field %s, %s", oField.GetNameRef(),
862 poDS->GetSession()->GetLastError() );
863
864 return OGRERR_FAILURE;
865 }
866
867 /* -------------------------------------------------------------------- */
868 /* Add the field to the OGRFeatureDefn. */
869 /* -------------------------------------------------------------------- */
870
871 poFeatureDefn->AddFieldDefn( &oField );
872 return OGRERR_NONE;
873 }
874
875 /************************************************************************/
876 /* ISetFeature() */
877 /* */
878 /* ISetFeature() is implemented by an UPDATE SQL command */
879 /************************************************************************/
880
ISetFeature(OGRFeature * poFeature)881 OGRErr OGRDB2TableLayer::ISetFeature( OGRFeature *poFeature )
882
883 {
884 OGRErr eErr = OGRERR_FAILURE;
885
886 GetLayerDefn();
887
888 if( nullptr == poFeature )
889 {
890 CPLError( CE_Failure, CPLE_AppDefined,
891 "NULL pointer to OGRFeature passed to SetFeature()." );
892 return eErr;
893 }
894
895 if( poFeature->GetFID() == OGRNullFID )
896 {
897 CPLError( CE_Failure, CPLE_AppDefined,
898 "FID required on features given to SetFeature()." );
899 return eErr;
900 }
901
902 if( !pszFIDColumn )
903 {
904 CPLError( CE_Failure, CPLE_AppDefined,
905 "Unable to update features in tables without\n"
906 "a recognised FID column.");
907 return eErr;
908 }
909
910 ClearStatement();
911
912 /* -------------------------------------------------------------------- */
913 /* Form the UPDATE command. */
914 /* -------------------------------------------------------------------- */
915 if (PrepareFeature(poFeature, 'U'))
916 return OGRERR_FAILURE;
917
918 int nFieldCount = poFeatureDefn->GetFieldCount();
919 int nBindNum = 0;
920 void** papBindBuffer = (void**)CPLMalloc(sizeof(void*) * nFieldCount);
921
922 /* Set the geometry */
923 OGRGeometry *poGeom = poFeature->GetGeometryRef();
924 char *pszWKT = nullptr;
925
926 if (poGeom != nullptr && pszGeomColumn != nullptr)
927 {
928 if( poGeom->exportToWkt( &pszWKT ) == OGRERR_NONE)
929 {
930 int nLen = (int) strlen(pszWKT);
931 if (m_poPrepStmt->DB2BindParameterIn(
932 "OGRDB2TableLayer::UpdateFeature",
933 (nBindNum + 1),
934 SQL_C_CHAR,
935 SQL_LONGVARCHAR,
936 nLen,
937 (void *)(pszWKT)))
938 {
939 papBindBuffer[nBindNum] = pszWKT;
940 nBindNum++;
941 } else {
942 CPLDebug("OGRDB2TableLayer::UpdateFeature",
943 "Bind parameter failed");
944 FreeBindBuffer(nBindNum, papBindBuffer);
945 return OGRERR_FAILURE;
946 }
947 }
948 }
949
950 for( int i = 0; i < nFieldCount; i++ )
951 {
952 // int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
953 // CPLDebug("OGRDB2TableLayer::UpdateFeature",
954 // "i: %d; nOGRFieldType: %d",
955 // i, nOGRFieldType);
956
957 if (BindFieldValue(m_poPrepStmt,
958 poFeature, i,
959 nBindNum, papBindBuffer) != OGRERR_NONE) {
960 CPLDebug("OGRDB2TableLayer::UpdateFeature",
961 "Bind parameter failed");
962 FreeBindBuffer(nBindNum, papBindBuffer);
963 return OGRERR_FAILURE;
964 }
965 nBindNum++;
966 }
967
968 /* -------------------------------------------------------------------- */
969 /* Execute the update. */
970 /* -------------------------------------------------------------------- */
971 if( !m_poPrepStmt->DB2Execute("OGR_DB2TableLayer::UpdateFeature") )
972 {
973 CPLError( CE_Failure, CPLE_AppDefined,
974 "Error updating feature with FID:" CPL_FRMT_GIB ", %s",
975 poFeature->GetFID(),
976 poDS->GetSession()->GetLastError() );
977
978 return OGRERR_FAILURE;
979 }
980
981 FreeBindBuffer(nBindNum, papBindBuffer);
982
983 return OGRERR_NONE;
984 }
985
986 /************************************************************************/
987 /* DeleteFeature() */
988 /************************************************************************/
989
DeleteFeature(GIntBig nFID)990 OGRErr OGRDB2TableLayer::DeleteFeature( GIntBig nFID )
991
992 {
993 CPLDebug("OGR_DB2TableLayer::DeleteFeature",
994 " entering, nFID: " CPL_FRMT_GIB,nFID);
995 GetLayerDefn();
996
997 if( pszFIDColumn == nullptr )
998 {
999 CPLError( CE_Failure, CPLE_AppDefined,
1000 "DeleteFeature() without any FID column." );
1001 return OGRERR_FAILURE;
1002 }
1003
1004 if( nFID == OGRNullFID )
1005 {
1006 CPLError( CE_Failure, CPLE_AppDefined,
1007 "DeleteFeature() with unset FID fails." );
1008 return OGRERR_FAILURE;
1009 }
1010
1011 ClearStatement();
1012
1013 /* -------------------------------------------------------------------- */
1014 /* Drop the record with this FID. */
1015 /* -------------------------------------------------------------------- */
1016 OGRDB2Statement oStatement( poDS->GetSession() );
1017
1018 oStatement.Appendf("DELETE FROM %s WHERE %s = " CPL_FRMT_GIB,
1019 poFeatureDefn->GetName(), pszFIDColumn, nFID);
1020 if( !oStatement.DB2Execute("OGR_DB2TableLayer::DeleteFeature") )
1021 {
1022 CPLError( CE_Failure, CPLE_AppDefined,
1023 "Attempt to delete feature with FID " CPL_FRMT_GIB
1024 " failed. %s",
1025 nFID, poDS->GetSession()->GetLastError() );
1026 return OGRERR_FAILURE;
1027 }
1028 return OGRERR_NONE;
1029 }
1030
1031 /************************************************************************/
1032 /* isFieldTypeSupported() */
1033 /************************************************************************/
1034
isFieldTypeSupported(OGRFieldType nFieldType)1035 OGRErr OGRDB2TableLayer::isFieldTypeSupported( OGRFieldType nFieldType )
1036
1037 {
1038 switch(nFieldType) {
1039 case OFTInteger:
1040 case OFTReal:
1041 case OFTString:
1042 case OFTDateTime:
1043 case OFTInteger64:
1044 return OGRERR_NONE;
1045 default:
1046 return OGRERR_FAILURE;
1047 }
1048 }
1049
1050 /************************************************************************/
1051 /* PrepareFeature() */
1052 /************************************************************************/
1053
PrepareFeature(OGRFeature * poFeature,char cType)1054 OGRErr OGRDB2TableLayer::PrepareFeature( OGRFeature *poFeature, char cType )
1055
1056 {
1057 // LATER - this defeats the point of prepared statements but need to find
1058 // some place to clean up to avoid reusing the wrong statement
1059 if (m_poPrepStmt) delete m_poPrepStmt;
1060 m_poPrepStmt = new OGRDB2Statement( poDS->GetSession());
1061
1062 char *pszWKT = nullptr;
1063 CPLString osValues= " VALUES(";
1064 int nFieldCount = poFeatureDefn->GetFieldCount();
1065
1066 if (cType == 'I')
1067 m_poPrepStmt->Appendf( "INSERT INTO %s.%s (",
1068 pszSchemaName, pszTableName );
1069 else
1070 m_poPrepStmt->Appendf( "UPDATE %s.%s SET ",
1071 pszSchemaName, pszTableName);
1072 int bNeedComma = FALSE;
1073 OGRGeometry *poGeom = poFeature->GetGeometryRef();
1074
1075 if (poGeom != nullptr && pszGeomColumn != nullptr)
1076 {
1077 if( poGeom->exportToWkt( &pszWKT ) == OGRERR_NONE)
1078 {
1079 int nLen = (int) strlen(pszWKT);
1080 if (cType == 'I')
1081 {
1082 m_poPrepStmt->Append( pszGeomColumn );
1083 CPLString geomValue;
1084 geomValue.Printf( "DB2GSE.ST_%s(CAST( ? AS CLOB(2M)),%d)",
1085 poGeom->getGeometryName(), nSRSId );
1086 osValues.append(geomValue);
1087 } else {
1088 m_poPrepStmt->Appendf( "%s = "
1089 "DB2GSE.ST_%s(CAST( ? AS CLOB(%d)),%d)",
1090 pszGeomColumn, poGeom->getGeometryName(),
1091 nLen, nSRSId );
1092 }
1093 bNeedComma = TRUE;
1094 }
1095 }
1096
1097 // Explicitly add FID column and value if needed
1098 if( cType == 'I' && poFeature->GetFID() != OGRNullFID
1099 && pszFIDColumn != nullptr && cGenerated != 'A' )
1100 {
1101 if (bNeedComma)
1102 {
1103 m_poPrepStmt->Appendf( ", ");
1104 osValues.append(", ");
1105 }
1106 m_poPrepStmt->Appendf( "%s", pszFIDColumn );
1107 osValues.append("?");
1108 bNeedComma = TRUE;
1109 }
1110
1111 for( int i = 0; i < nFieldCount; i++ )
1112 {
1113
1114 if( !poFeature->IsFieldSetAndNotNull( i ) )
1115 continue;
1116
1117 if (bNeedComma)
1118 {
1119 m_poPrepStmt->Appendf( ", ");
1120 osValues.append(", ");
1121 }
1122 bNeedComma = TRUE;
1123 if (cType == 'I') {
1124 m_poPrepStmt->Appendf( "%s",
1125 poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1126 osValues.append("?");
1127 } else {
1128 m_poPrepStmt->Appendf( "%s = ?",
1129 poFeatureDefn->GetFieldDefn(i)->GetNameRef());
1130 }
1131 }
1132 if (cType == 'I') {
1133 m_poPrepStmt->Appendf( ") %s )", osValues.c_str() );
1134 } else {
1135 /* Add the WHERE clause */
1136 m_poPrepStmt->Appendf( " WHERE (%s) = " CPL_FRMT_GIB, pszFIDColumn,
1137 poFeature->GetFID());
1138 }
1139 if (!m_poPrepStmt->DB2Prepare("OGR_DB2TableLayer::PrepareFeature"))
1140 {
1141 CPLError( CE_Failure, CPLE_AppDefined,
1142 "PREPARE command for feature failed. %s",
1143 poDS->GetSession()->GetLastError() );
1144 return OGRERR_FAILURE;
1145 }
1146
1147 return OGRERR_NONE;
1148 }
1149
1150 /************************************************************************/
1151 /* ICreateFeature() */
1152 /************************************************************************/
1153
ICreateFeature(OGRFeature * poFeature)1154 OGRErr OGRDB2TableLayer::ICreateFeature( OGRFeature *poFeature )
1155 {
1156 GetLayerDefn();
1157
1158 if( nullptr == poFeature )
1159 {
1160 CPLError( CE_Failure, CPLE_AppDefined,
1161 "NULL pointer to OGRFeature passed to CreateFeature()." );
1162 return OGRERR_FAILURE;
1163 }
1164
1165 if (PrepareFeature(poFeature, 'I'))
1166 return OGRERR_FAILURE;
1167
1168 char *pszWKT = nullptr;
1169 int nFieldCount = poFeatureDefn->GetFieldCount();
1170 int nBindNum = 0;
1171 void** papBindBuffer = (void**)CPLMalloc(sizeof(void*)
1172 * (nFieldCount + 1));
1173 OGRGeometry *poGeom = poFeature->GetGeometryRef();
1174
1175 if (poGeom != nullptr && pszGeomColumn != nullptr)
1176 {
1177 if( poGeom->exportToWkt( &pszWKT ) == OGRERR_NONE)
1178 {
1179 int nLen = (int) strlen(pszWKT);
1180 if (m_poPrepStmt->DB2BindParameterIn(
1181 "OGRDB2TableLayer::ICreateFeature",
1182 (nBindNum + 1),
1183 SQL_C_CHAR,
1184 SQL_LONGVARCHAR,
1185 nLen,
1186 (void *)(pszWKT)))
1187 {
1188 papBindBuffer[nBindNum] = pszWKT;
1189 nBindNum++;
1190 }
1191 else
1192 {
1193 CPLDebug("OGRDB2TableLayer::ICreateFeature",
1194 "Bind parameter failed");
1195 FreeBindBuffer(nBindNum, papBindBuffer);
1196 return OGRERR_FAILURE;
1197 }
1198 }
1199 }
1200
1201 // Explicitly add FID column and value if needed
1202 if( poFeature->GetFID() != OGRNullFID
1203 && pszFIDColumn != nullptr && cGenerated != 'A' )
1204 {
1205 GIntBig nFID = poFeature->GetFID();
1206 if (m_poPrepStmt->DB2BindParameterIn(
1207 "OGRDB2TableLayer::ICreateFeature",
1208 (nBindNum + 1),
1209 SQL_C_SBIGINT,
1210 SQL_BIGINT,
1211 sizeof(GIntBig),
1212 (void *)(&nFID)))
1213 {
1214 papBindBuffer[nBindNum] = nullptr;
1215 nBindNum++;
1216 }
1217 else
1218 {
1219 CPLDebug("OGRDB2TableLayer::ICreateFeature",
1220 "Bind parameter failed");
1221 FreeBindBuffer(nBindNum, papBindBuffer);
1222 return OGRERR_FAILURE;
1223 }
1224 }
1225
1226 for( int i = 0; i < nFieldCount; i++ )
1227 {
1228
1229 if( !poFeature->IsFieldSetAndNotNull( i ) )
1230 continue;
1231
1232 // int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
1233 // CPLDebug("OGRDB2TableLayer::ICreateFeature",
1234 // "i: %d; nOGRFieldType: %d",
1235 // i, nOGRFieldType);
1236
1237 if (BindFieldValue(m_poPrepStmt,
1238 poFeature, i,
1239 nBindNum, papBindBuffer) != OGRERR_NONE) {
1240 CPLDebug("OGRDB2TableLayer::ICreateFeature",
1241 "Bind parameter failed");
1242 FreeBindBuffer(nBindNum, papBindBuffer);
1243 return OGRERR_FAILURE;
1244 }
1245 nBindNum++;
1246 }
1247
1248 poDS->getDTime();
1249 /* -------------------------------------------------------------------- */
1250 /* Execute the insert. */
1251 /* -------------------------------------------------------------------- */
1252
1253 if (!m_poPrepStmt->DB2Execute("OGR_DB2TableLayer::ICreateFeature"))
1254 {
1255 CPLError( CE_Failure, CPLE_AppDefined,
1256 "INSERT command for new feature failed. %s",
1257 poDS->GetSession()->GetLastError() );
1258 FreeBindBuffer(nBindNum, papBindBuffer);
1259 return OGRERR_FAILURE;
1260 }
1261 poDS->getDTime();
1262
1263 if( bIsIdentityFid) {
1264 GIntBig oldFID = poFeature->GetFID();
1265 OGRDB2Statement oStatement2( poDS->GetSession() );
1266 oStatement2.Append( "select IDENTITY_VAL_LOCAL() AS IDENTITY "
1267 "FROM SYSIBM.SYSDUMMY1");
1268 if( oStatement2.DB2Execute("OGR_DB2TableLayer::ICreateFeature")
1269 && oStatement2.Fetch() )
1270 {
1271 poFeature->SetFID( atoi(oStatement2.GetColData( 0 ) ));
1272
1273 if ( oStatement2.GetColData( 0 ) )
1274 {
1275 poFeature->SetFID( atoi(oStatement2.GetColData( 0 ) ));
1276 }
1277 }
1278 CPLDebug("OGR_DB2TableLayer::ICreateFeature","Old FID: " CPL_FRMT_GIB
1279 "; New FID: " CPL_FRMT_GIB, oldFID, poFeature->GetFID());
1280 }
1281
1282 FreeBindBuffer(nBindNum, papBindBuffer);
1283
1284 return OGRERR_NONE;
1285 }
1286
1287 /************************************************************************/
1288 /* FreeBindBuffer() */
1289 /************************************************************************/
1290
FreeBindBuffer(int nBindNum,void ** papBindBuffer)1291 void OGRDB2TableLayer::FreeBindBuffer(int nBindNum, void **papBindBuffer)
1292 {
1293 for( int i = 0; i < nBindNum; i++ ) {
1294 if (papBindBuffer[i] ) CPLFree(papBindBuffer[i]); // only free if set
1295 };
1296 CPLFree(papBindBuffer);
1297 }
1298
1299 /************************************************************************/
1300 /* BindFieldValue() */
1301 /* */
1302 /* Used by CreateFeature() and SetFeature() to bind a */
1303 /* non-empty field value */
1304 /************************************************************************/
1305
BindFieldValue(OGRDB2Statement *,OGRFeature * poFeature,int i,int nBindNum,void ** papBindBuffer)1306 OGRErr OGRDB2TableLayer::BindFieldValue(OGRDB2Statement * /*poStatement*/,
1307 OGRFeature* poFeature, int i,
1308 int nBindNum, void **papBindBuffer)
1309 {
1310 int nOGRFieldType = poFeatureDefn->GetFieldDefn(i)->GetType();
1311
1312 int nLen = 0;
1313 void * pValuePointer = nullptr;
1314 int nValueType = 0;
1315 int nParameterType = 0;
1316
1317 if( nOGRFieldType == OFTString ) {
1318 const char* stringValue = poFeature->GetFieldAsString(i);
1319 papBindBuffer[nBindNum] = nullptr; // Don't free
1320 nLen = (int) strlen(stringValue);
1321 pValuePointer = (void *) stringValue;
1322 nValueType = SQL_C_CHAR;
1323 nParameterType = SQL_VARCHAR;
1324 }
1325
1326 if ( nOGRFieldType == OFTReal ) {
1327 double *pnRealValue = (double *)CPLMalloc(sizeof(double));
1328 papBindBuffer[nBindNum] = pnRealValue;
1329 *pnRealValue = poFeature->GetFieldAsInteger(i);
1330 nLen = sizeof(double);
1331 pValuePointer = (void *) pnRealValue;
1332 nValueType = SQL_C_DOUBLE;
1333 nParameterType = SQL_DOUBLE;
1334 }
1335
1336 if ( nOGRFieldType == OFTInteger ) {
1337 int *pnIntValue = (int *)CPLMalloc(sizeof(int));
1338 papBindBuffer[nBindNum] = pnIntValue;
1339 *pnIntValue = poFeature->GetFieldAsInteger(i);
1340 nLen = sizeof(int);
1341 pValuePointer = (void *) pnIntValue;
1342 nValueType = SQL_C_SLONG;
1343 nParameterType = SQL_INTEGER;
1344 }
1345
1346 if ( nOGRFieldType == OFTInteger64 ) {
1347 GIntBig *pnLongValue = (GIntBig *)CPLMalloc(sizeof(GIntBig));
1348 papBindBuffer[nBindNum] = pnLongValue;
1349 *pnLongValue = poFeature->GetFieldAsInteger64(i);
1350 nLen = sizeof(GIntBig);
1351 pValuePointer = (void *) pnLongValue;
1352 nValueType = SQL_C_SBIGINT;
1353 nParameterType = SQL_BIGINT;
1354 }
1355
1356 if (pValuePointer) {
1357 if (!m_poPrepStmt->DB2BindParameterIn(
1358 "OGRDB2TableLayer::BindFieldValue",
1359 (nBindNum + 1),
1360 nValueType,
1361 nParameterType,
1362 nLen,
1363 pValuePointer))
1364 {
1365 CPLDebug("OGRDB2TableLayer::BindFieldValue",
1366 "Bind parameter failed");
1367 return OGRERR_FAILURE;
1368 }
1369 }
1370 return OGRERR_NONE;
1371 }
1372
1373 #ifdef notdef
1374 /************************************************************************/
1375 /* CreateSpatialIndexIfNecessary() */
1376 /************************************************************************/
1377
CreateSpatialIndexIfNecessary()1378 void OGRDB2TableLayer::CreateSpatialIndexIfNecessary()
1379 {
1380 if( bDeferredSpatialIndexCreation )
1381 {
1382 CreateSpatialIndex();
1383 }
1384 }
1385 #endif
1386
1387 /************************************************************************/
1388 /* RunDeferredCreationIfNecessary() */
1389 /************************************************************************/
1390
RunDeferredCreationIfNecessary()1391 OGRErr OGRDB2TableLayer::RunDeferredCreationIfNecessary()
1392 {
1393 CPLDebug("OGRDB2TableLayer::RunDeferredCreationIfNecessary","NO-OP");
1394 #ifdef LATER
1395 if( !m_bDeferredCreation )
1396 return OGRERR_NONE;
1397 m_bDeferredCreation = FALSE;
1398
1399 const char* pszLayerName = m_poFeatureDefn->GetName();
1400 OGRwkbGeometryType eGType = GetGeomType();
1401
1402 int bIsSpatial = (eGType != wkbNone);
1403
1404 /* Requirement 25: The geometry_type_name value in a gpkg_geometry_columns */
1405 /* row SHALL be one of the uppercase geometry type names specified in */
1406 /* Geometry Types (Normative). */
1407 const char *pszGeometryType = m_poDS->GetGeometryTypeString(eGType);
1408
1409 /* Create the table! */
1410 char *pszSQL = NULL;
1411 CPLString osCommand;
1412
1413 pszSQL = sqlite3_mprintf(
1414 "CREATE TABLE \"%s\" ( "
1415 "\"%s\" INTEGER PRIMARY KEY AUTOINCREMENT",
1416 pszLayerName, m_pszFidColumn);
1417 osCommand += pszSQL;
1418 sqlite3_free(pszSQL);
1419
1420 if( GetGeomType() != wkbNone )
1421 {
1422 pszSQL = sqlite3_mprintf(", '%q' %s",
1423 GetGeometryColumn(), pszGeometryType);
1424 osCommand += pszSQL;
1425 sqlite3_free(pszSQL);
1426 if( !m_poFeatureDefn->GetGeomFieldDefn(0)->IsNullable() )
1427 {
1428 osCommand += " NOT NULL";
1429 }
1430 }
1431
1432 for(int i = 0; i < m_poFeatureDefn->GetFieldCount(); i++ )
1433 {
1434 if( i == m_iFIDAsRegularColumnIndex )
1435 continue;
1436 OGRFieldDefn* poFieldDefn = m_poFeatureDefn->GetFieldDefn(i);
1437 pszSQL = sqlite3_mprintf(", '%q' %s",
1438 poFieldDefn->GetNameRef(),
1439 GPkgFieldFromOGR(poFieldDefn->GetType(),
1440 poFieldDefn->GetSubType(),
1441 poFieldDefn->GetWidth()));
1442 osCommand += pszSQL;
1443 sqlite3_free(pszSQL);
1444 if( !poFieldDefn->IsNullable() )
1445 {
1446 osCommand += " NOT NULL";
1447 }
1448 const char* pszDefault = poFieldDefn->GetDefault();
1449 if( pszDefault != NULL &&
1450 (!poFieldDefn->IsDefaultDriverSpecific() ||
1451 (pszDefault[0] == '('
1452 && pszDefault[strlen(pszDefault)-1] == ')'
1453 && (STARTS_WITH_CI(pszDefault+1, "strftime")
1454 || STARTS_WITH_CI(pszDefault+1, " strftime")))) )
1455 {
1456 osCommand += " DEFAULT ";
1457 OGRField sField;
1458 if( poFieldDefn->GetType() == OFTDateTime &&
1459 OGRParseDate(pszDefault, &sField, 0) )
1460 {
1461 char* pszXML = OGRGetXMLDateTime(&sField);
1462 osCommand += pszXML;
1463 CPLFree(pszXML);
1464 }
1465 /* Make sure CURRENT_TIMESTAMP is translated into appropriate format */
1466 /* for GeoPackage */
1467 else if( poFieldDefn->GetType() == OFTDateTime &&
1468 EQUAL(pszDefault, "CURRENT_TIMESTAMP") )
1469 {
1470 osCommand += "(strftime('%Y-%m-%dT%H:%M:%fZ','now'))";
1471 }
1472 else
1473 {
1474 osCommand += poFieldDefn->GetDefault();
1475 }
1476 }
1477 }
1478
1479 osCommand += ")";
1480
1481 OGRErr err = SQLCommand(m_poDS->GetDB(), osCommand.c_str());
1482 if ( OGRERR_NONE != err )
1483 return OGRERR_FAILURE;
1484
1485 /* Update gpkg_contents with the table info */
1486 if ( bIsSpatial )
1487 err = RegisterGeometryColumn();
1488 else
1489 err = m_poDS->CreateGDALAspatialExtension();
1490
1491 if ( err != OGRERR_NONE )
1492 return OGRERR_FAILURE;
1493
1494 const char* pszIdentifier = GetMetadataItem("IDENTIFIER");
1495 if( pszIdentifier == NULL )
1496 pszIdentifier = pszLayerName;
1497 const char* pszDescription = GetMetadataItem("DESCRIPTION");
1498 if( pszDescription == NULL )
1499 pszDescription = "";
1500 pszSQL = sqlite3_mprintf(
1501 "INSERT INTO gpkg_contents "
1502 "(table_name,data_type,identifier,description,"
1503 "last_change,srs_id)"
1504 " VALUES "
1505 "('%q','%q','%q','%q',strftime('%%Y-%%m-%%dT%%H:%%M:%%fZ',"
1506 "CURRENT_TIMESTAMP),%d)",
1507 pszLayerName, (bIsSpatial ? "features": "aspatial"),
1508 pszIdentifier, pszDescription, m_iSrs);
1509
1510 err = SQLCommand(m_poDS->GetDB(), pszSQL);
1511 sqlite3_free(pszSQL);
1512 if ( err != OGRERR_NONE )
1513 return OGRERR_FAILURE;
1514
1515 ResetReading();
1516 #endif
1517 return OGRERR_NONE;
1518 }
1519