Index: gdal/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h =================================================================== --- gdal/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h (Revision 27538) +++ gdal/ogr/ogrsf_frmts/sqlite/ogr_sqlite.h (Arbeitskopie) @@ -466,8 +466,27 @@ void BuildWhere(void); virtual OGRErr ResetStatement(); - + // added for SpatialView - writable + int bTriggerInsert; + int bTriggerUpdate; + int bTriggerDelete; CPLErr EstablishFeatureDefn(); + OGRwkbGeometryType eGeomType; + char *pszGeomCol; + int bStatisticsNeedsToBeFlushed; + int bCachedExtentIsValid; + OGREnvelope oCachedExtent; + sqlite3_stmt *hInsertStmt; + CPLString osLastInsertStmt; + int nSRSId; + OGRSpatialReference *poSRS; + int bSpatialite2D; + GIntBig nFeatureCount; /* if -1, means not up-to-date */ + // functions + OGRErr BindValues( OGRFeature *poFeature, + sqlite3_stmt* hStmt, + int bBindNullValues ); + void ClearInsertStmt(); public: OGRSQLiteViewLayer( OGRSQLiteDataSource * ); @@ -480,7 +499,9 @@ const char *pszViewGeometry, const char *pszViewRowid, const char *pszTableName, - const char *pszGeometryColumn); + const char *pszGeometryColumn, + OGRSpatialReference *poSRS, + int nSRSId = UNINITIALIZED_SRID); virtual OGRFeatureDefn *GetLayerDefn(); int HasLayerDefnError() { GetLayerDefn(); return bLayerDefnError; } @@ -490,6 +511,9 @@ virtual void SetSpatialFilter( OGRGeometry * ); virtual OGRErr SetAttributeFilter( const char * ); + virtual OGRErr SetFeature( OGRFeature *poFeature ); + virtual OGRErr DeleteFeature( long nFID ); + virtual OGRErr CreateFeature( OGRFeature *poFeature ); virtual OGRFeature *GetFeature( long nFeatureId ); @@ -747,7 +771,9 @@ const char *pszViewGeometry, const char *pszViewRowid, const char *pszTableName, - const char *pszGeometryColumn); + const char *pszGeometryColumn, + OGRSpatialReference *poSRS = NULL, + int nSRID = UNINITIALIZED_SRID); virtual int GetLayerCount() { return nLayers; } virtual OGRLayer *GetLayer( int ); Index: gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp =================================================================== --- gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp (Revision 27538) +++ gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitetablelayer.cpp (Arbeitskopie) @@ -1787,7 +1787,7 @@ poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay, &nHour, &nMinute, &nSecond, &nTZ); char szBuffer[64]; - sprintf(szBuffer, "%04d-%02d-%02dT", nYear, nMonth, nDay); + sprintf(szBuffer, "%04d-%02d-%02d", nYear, nMonth, nDay); rc = sqlite3_bind_text(hStmt, nBindField++, szBuffer, -1, SQLITE_TRANSIENT); break; Index: gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp =================================================================== --- gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp (Revision 27538) +++ gdal/ogr/ogrsf_frmts/sqlite/ogrsqlitedatasource.cpp (Arbeitskopie) @@ -1329,19 +1329,20 @@ /* Detect spatial views */ /* -------------------------------------------------------------------- */ rc = sqlite3_get_table( hDB, - "SELECT view_name, view_geometry, view_rowid, f_table_name, f_geometry_column FROM views_geometry_columns", + "SELECT view_name, view_geometry, view_rowid, f_table_name, f_geometry_column,srid FROM views_geometry_columns INNER JOIN vector_layers ON (view_name=table_name AND f_geometry_column=geometry_column)", &papszResult, &nRowCount, &nColCount, &pszErrMsg ); if ( rc == SQLITE_OK ) { for( iRow = 0; iRow < nRowCount; iRow++ ) { - char **papszRow = papszResult + iRow * 5 + 5; + char **papszRow = papszResult + iRow * 6 + 6; const char* pszViewName = papszRow[0]; const char* pszViewGeometry = papszRow[1]; const char* pszViewRowid = papszRow[2]; const char* pszTableName = papszRow[3]; const char* pszGeometryColumn = papszRow[4]; + int nSRID = atoi(papszRow[5]); if (pszViewName == NULL || pszViewGeometry == NULL || @@ -1351,7 +1352,7 @@ continue; OpenView( pszViewName, pszViewGeometry, pszViewRowid, - pszTableName, pszGeometryColumn ); + pszTableName, pszGeometryColumn,FetchSRS(nSRID),nSRID ); if (bListAllTables) CPLHashSetInsert(hSet, CPLStrdup(pszViewName)); @@ -1501,7 +1502,8 @@ const char *pszViewGeometry, const char *pszViewRowid, const char *pszTableName, - const char *pszGeometryColumn) + const char *pszGeometryColumn, + OGRSpatialReference *poSRS, int nSRID) { /* -------------------------------------------------------------------- */ @@ -1512,7 +1514,7 @@ poLayer = new OGRSQLiteViewLayer( this ); if( poLayer->Initialize( pszViewName, pszViewGeometry, - pszViewRowid, pszTableName, pszGeometryColumn ) != CE_None ) + pszViewRowid, pszTableName, pszGeometryColumn,poSRS,nSRID ) != CE_None ) { delete poLayer; return FALSE; Index: gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp =================================================================== --- gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp (Revision 27538) +++ gdal/ogr/ogrsf_frmts/sqlite/ogrsqliteviewlayer.cpp (Arbeitskopie) @@ -32,6 +32,8 @@ #include "ogr_sqlite.h" #include +#define UNSUPPORTED_OP_READ_ONLY "%s : unsupported operation on a read-only datasource." + CPL_CVSID("$Id$"); /************************************************************************/ @@ -53,6 +55,20 @@ bHasCheckedSpatialIndexTable = FALSE; bLayerDefnError = FALSE; + // added for SpatialView - writable + bTriggerInsert = FALSE; + bTriggerUpdate = FALSE; + bTriggerDelete = FALSE; + hInsertStmt = NULL; + eGeomType = wkbUnknown; + bLayerDefnError = FALSE; + bStatisticsNeedsToBeFlushed = FALSE; + bCachedExtentIsValid = FALSE; + nFeatureCount = -1; + eGeomFormat = OSGF_None; + pszGeomCol = NULL; + nSRSId = UNINITIALIZED_SRID; + poSRS = NULL; } /************************************************************************/ @@ -63,12 +79,28 @@ { ClearStatement(); + ClearInsertStmt(); + CPLFree(pszGeomCol); CPLFree(pszViewName); CPLFree(pszEscapedTableName); CPLFree(pszEscapedUnderlyingTableName); } /************************************************************************/ +/* ClearInsertStmt() */ +/************************************************************************/ + +void OGRSQLiteViewLayer::ClearInsertStmt() +{ + if( hInsertStmt != NULL ) + { + sqlite3_finalize( hInsertStmt ); + hInsertStmt = NULL; + } + osLastInsertStmt = ""; +} + +/************************************************************************/ /* Initialize() */ /************************************************************************/ @@ -76,7 +108,9 @@ const char *pszViewGeometry, const char *pszViewRowid, const char *pszUnderlyingTableName, - const char *pszUnderlyingGeometryColumn) + const char *pszUnderlyingGeometryColumn, + OGRSpatialReference *poSRS, + int nSRSId) { this->pszViewName = CPLStrdup(pszViewName); @@ -94,6 +128,12 @@ //this->bHasM = bHasM; + if( nSRSId == UNINITIALIZED_SRID ) + nSRSId = poDS->GetUndefinedSRID(); + + this->poSRS = poSRS; + this->nSRSId = nSRSId; + pszEscapedTableName = CPLStrdup(OGRSQLiteEscape(pszViewName)); pszEscapedUnderlyingTableName = CPLStrdup(OGRSQLiteEscape(pszUnderlyingTableName)); @@ -203,6 +243,36 @@ this->bHasSpatialIndex = poUnderlyingLayer->HasSpatialIndex(); + // added for SpatialView - writable + // mj10777: check for triggers for INSERT,UPDATE and DELETE + // - it is NOT possible to check the validity of these triggers + int nRowCount = 0, nColCount = 0; + char** papszResult = NULL; + pszSQL = CPLSPrintf( "SELECT count(sql) FROM sqlite_master WHERE ((type = 'trigger' AND tbl_name='%s') AND (sql LIKE '%%INSTEAD OF INSERT%%'))",pszEscapedTableName ); + sqlite3_get_table( hDB,pszSQL,&papszResult, &nRowCount, &nColCount,NULL ); + sqlite3_free_table(papszResult); + papszResult = NULL; + if( nRowCount > 0 ) + { // mj10777: trigger for 'INSTEAD OF INSERT' + bTriggerInsert = TRUE; + } + pszSQL = CPLSPrintf( "SELECT count(sql) FROM sqlite_master WHERE ((type = 'trigger' AND tbl_name='%s') AND (sql LIKE '%%INSTEAD OF UPDATE%%'))",pszEscapedTableName ); + sqlite3_get_table( hDB,pszSQL,&papszResult, &nRowCount, &nColCount,NULL ); + sqlite3_free_table(papszResult); + papszResult = NULL; + if( nRowCount > 0 ) + { // mj10777: trigger for 'INSTEAD OF UPDATE' + bTriggerUpdate = TRUE; + } + pszSQL = CPLSPrintf( "SELECT count(sql) FROM sqlite_master WHERE ((type = 'trigger' AND tbl_name='%s') AND (sql LIKE '%%INSTEAD OF DELETE%%'))",pszEscapedTableName ); + sqlite3_get_table( hDB,pszSQL,&papszResult, &nRowCount, &nColCount,NULL ); + sqlite3_free_table(papszResult); + papszResult = NULL; + if( nRowCount > 0 ) + { // mj10777: trigger for 'INSTEAD OF DELETE' + bTriggerDelete = TRUE; + } + /* -------------------------------------------------------------------- */ /* Get the column definitions for this table. */ /* -------------------------------------------------------------------- */ @@ -232,6 +302,19 @@ } /* -------------------------------------------------------------------- */ +/* What should we use as FID? If there is a primary key */ +/* integer field, then this will be used as the _rowid_, and we */ +/* will pick up the real column name here. Otherwise, we will */ +/* just use fid. */ +/* */ +/* Note that the select _rowid_ will return the real column */ +/* name if the rowid corresponds to another primary key */ +/* column. */ +/* -------------------------------------------------------------------- */ + CPLFree( pszFIDColumn ); + pszFIDColumn = CPLStrdup(OGRSQLiteParamsUnquote(sqlite3_column_name( hColStmt, 0 ))); + +/* -------------------------------------------------------------------- */ /* Collect the rest of the fields. */ /* -------------------------------------------------------------------- */ std::set aosEmpty; @@ -247,6 +330,8 @@ OGRSQLiteGeomFieldDefn* poGeomFieldDefn = poFeatureDefn->myGetGeomFieldDefn(0); poGeomFieldDefn->SetSpatialRef(poUnderlyingLayer->GetSpatialRef()); + if( pszGeomCol == NULL ) + pszGeomCol = CPLStrdup( poGeomFieldDefn->GetNameRef() ); poGeomFieldDefn->nSRSId = poUnderlyingLayer->myGetLayerDefn()-> myGetGeomFieldDefn(0)->nSRSId; if( eGeomFormat != OSGF_None ) @@ -257,6 +342,624 @@ } /************************************************************************/ +/* BindValues() */ +/************************************************************************/ + +/* the bBindNullValues is set to TRUE by SetFeature() for UPDATE statements, */ +/* and to FALSE by CreateFeature() for INSERT statements; */ + +OGRErr OGRSQLiteViewLayer::BindValues( OGRFeature *poFeature, + sqlite3_stmt* hStmt, + int bBindNullValues ) +{ + int rc; + sqlite3 *hDB = poDS->GetDB(); + +/* -------------------------------------------------------------------- */ +/* Bind the geometry */ +/* -------------------------------------------------------------------- */ + int nBindField = 1; + + if( poFeatureDefn->GetGeomFieldCount() != 0 && + eGeomFormat != OSGF_FGF ) + { + OGRGeometry* poGeom = poFeature->GetGeometryRef(); + if ( poGeom != NULL ) + { + if ( eGeomFormat == OSGF_WKT ) + { + char *pszWKT = NULL; + poGeom->exportToWkt( &pszWKT ); + rc = sqlite3_bind_text( hStmt, nBindField++, pszWKT, -1, CPLFree ); + } + else if( eGeomFormat == OSGF_WKB ) + { + int nWKBLen = poGeom->WkbSize(); + GByte *pabyWKB = (GByte *) CPLMalloc(nWKBLen + 1); + + poGeom->exportToWkb( wkbNDR, pabyWKB ); + rc = sqlite3_bind_blob( hStmt, nBindField++, pabyWKB, nWKBLen, CPLFree ); + } + else if ( eGeomFormat == OSGF_SpatiaLite ) + { + int nBLOBLen; + GByte *pabySLBLOB; + + if( nSRSId == UNINITIALIZED_SRID ) + nSRSId = poDS->GetUndefinedSRID(); + + ExportSpatiaLiteGeometry( poGeom, nSRSId, wkbNDR, bHasM, + bSpatialite2D, bUseComprGeom, &pabySLBLOB, &nBLOBLen ); + rc = sqlite3_bind_blob( hStmt, nBindField++, pabySLBLOB, + nBLOBLen, CPLFree ); + } + else + { + rc = SQLITE_OK; + CPLAssert(0); + } + } + else + { + if (bBindNullValues) + rc = sqlite3_bind_null( hStmt, nBindField++ ); + else + rc = SQLITE_OK; + } + + if( rc != SQLITE_OK ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "sqlite3_bind_blob/text() failed:\n %s", + sqlite3_errmsg(hDB) ); + return OGRERR_FAILURE; + } + } + +/* -------------------------------------------------------------------- */ +/* Bind field values. */ +/* -------------------------------------------------------------------- */ + int iField; + int nFieldCount = poFeatureDefn->GetFieldCount(); + for( iField = 0; iField < nFieldCount; iField++ ) + { + const char *pszRawValue; + + if( !poFeature->IsFieldSet( iField ) ) + { + if (bBindNullValues) + rc = sqlite3_bind_null( hStmt, nBindField++ ); + else + rc = SQLITE_OK; + } + else + { + switch( poFeatureDefn->GetFieldDefn(iField)->GetType() ) + { + case OFTInteger: + { + int nFieldVal = poFeature->GetFieldAsInteger( iField ); + rc = sqlite3_bind_int(hStmt, nBindField++, nFieldVal); + break; + } + + case OFTReal: + { + double dfFieldVal = poFeature->GetFieldAsDouble( iField ); + rc = sqlite3_bind_double(hStmt, nBindField++, dfFieldVal); + break; + } + + case OFTBinary: + { + int nDataLength = 0; + GByte* pabyData = + poFeature->GetFieldAsBinary( iField, &nDataLength ); + rc = sqlite3_bind_blob(hStmt, nBindField++, + pabyData, nDataLength, SQLITE_TRANSIENT); + break; + } + + case OFTDateTime: + { + int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ; + poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay, + &nHour, &nMinute, &nSecond, &nTZ); + char szBuffer[64]; + sprintf(szBuffer, "%04d-%02d-%02dT%02d:%02d:%02d", + nYear, nMonth, nDay, nHour, nMinute, nSecond); + rc = sqlite3_bind_text(hStmt, nBindField++, + szBuffer, -1, SQLITE_TRANSIENT); + break; + } + + case OFTDate: + { + int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ; + poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay, + &nHour, &nMinute, &nSecond, &nTZ); + char szBuffer[64]; + sprintf(szBuffer, "%04d-%02d-%02d", nYear, nMonth, nDay); + rc = sqlite3_bind_text(hStmt, nBindField++, + szBuffer, -1, SQLITE_TRANSIENT); + break; + } + + case OFTTime: + { + int nYear, nMonth, nDay, nHour, nMinute, nSecond, nTZ; + poFeature->GetFieldAsDateTime(iField, &nYear, &nMonth, &nDay, + &nHour, &nMinute, &nSecond, &nTZ); + char szBuffer[64]; + sprintf(szBuffer, "%02d:%02d:%02d", nHour, nMinute, nSecond); + rc = sqlite3_bind_text(hStmt, nBindField++, + szBuffer, -1, SQLITE_TRANSIENT); + break; + } + + case OFTStringList: + { + char** papszValues = poFeature->GetFieldAsStringList( iField ); + CPLString osValue; + osValue += CPLSPrintf("(%d:", CSLCount(papszValues)); + for(int i=0; papszValues[i] != NULL; i++) + { + if( i != 0 ) + osValue += ","; + osValue += papszValues[i]; + } + osValue += ")"; + rc = sqlite3_bind_text(hStmt, nBindField++, + osValue.c_str(), -1, SQLITE_TRANSIENT); + break; + } + + default: + { + pszRawValue = poFeature->GetFieldAsString( iField ); + if( CSLFindString(papszCompressedColumns, + poFeatureDefn->GetFieldDefn(iField)->GetNameRef()) >= 0 ) + { + size_t nBytesOut = 0; + void* pOut = CPLZLibDeflate( pszRawValue, + strlen(pszRawValue), -1, + NULL, 0, + &nBytesOut ); + if( pOut != NULL ) + { + rc = sqlite3_bind_blob(hStmt, nBindField++, + pOut, + nBytesOut, + CPLFree); + } + else + rc = SQLITE_ERROR; + } + else + { + rc = sqlite3_bind_text(hStmt, nBindField++, + pszRawValue, -1, SQLITE_TRANSIENT); + } + break; + } + } + } + + if( rc != SQLITE_OK ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "sqlite3_bind_() for column %s failed:\n %s", + poFeatureDefn->GetFieldDefn(iField)->GetNameRef(), + sqlite3_errmsg(hDB) ); + return OGRERR_FAILURE; + } + } + + return OGRERR_NONE; +} + +/************************************************************************/ +/* SetFeature() */ +/************************************************************************/ + +OGRErr OGRSQLiteViewLayer::SetFeature( OGRFeature *poFeature ) + +{ + if (!bTriggerUpdate) + return OGRERR_FAILURE; // mj10777: no trigger for 'INSTEAD OF UPDATE' + + if (HasLayerDefnError()) + return OGRERR_FAILURE; + + if( pszFIDColumn == NULL ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "SetFeature() without any FID column." ); + return OGRERR_FAILURE; + } + + if( poFeature->GetFID() == OGRNullFID ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "SetFeature() with unset FID fails." ); + return OGRERR_FAILURE; + } + + if (!poDS->GetUpdate()) + { + CPLError( CE_Failure, CPLE_NotSupported, + UNSUPPORTED_OP_READ_ONLY, + "SetFeature"); + return OGRERR_FAILURE; + } + + sqlite3 *hDB = poDS->GetDB(); + CPLString osCommand; + int bNeedComma = FALSE; + + ResetReading(); + +/* -------------------------------------------------------------------- */ +/* Form the UPDATE command. */ +/* -------------------------------------------------------------------- */ + osCommand += CPLSPrintf( "UPDATE '%s' SET ", pszEscapedTableName ); + +/* -------------------------------------------------------------------- */ +/* Add geometry field name. */ +/* -------------------------------------------------------------------- */ + if( poFeatureDefn->GetGeomFieldCount() != 0 && + eGeomFormat != OSGF_FGF ) + { + osCommand += "\""; + osCommand += OGRSQLiteEscapeName(pszGeomCol); + osCommand += "\" = ?"; + + bNeedComma = TRUE; + } + +/* -------------------------------------------------------------------- */ +/* Add field names. */ +/* -------------------------------------------------------------------- */ + int iField; + int nFieldCount = poFeatureDefn->GetFieldCount(); + + for( iField = 0; iField < nFieldCount; iField++ ) + { + if( bNeedComma ) + osCommand += ","; + + osCommand += "\""; + osCommand += OGRSQLiteEscapeName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()); + osCommand += "\" = ?"; + + bNeedComma = TRUE; + } + + if (!bNeedComma) + return OGRERR_NONE; + +/* -------------------------------------------------------------------- */ +/* Merge final command. */ +/* -------------------------------------------------------------------- */ + osCommand += " WHERE \""; + osCommand += OGRSQLiteEscapeName(pszFIDColumn); + osCommand += CPLSPrintf("\" = %ld", poFeature->GetFID()); + +/* -------------------------------------------------------------------- */ +/* Prepare the statement. */ +/* -------------------------------------------------------------------- */ + int rc; + sqlite3_stmt *hUpdateStmt; + +#ifdef DEBUG + CPLDebug( "OGR_SQLITE", "prepare(%s)", osCommand.c_str() ); +#endif + + rc = sqlite3_prepare( hDB, osCommand, -1, &hUpdateStmt, NULL ); + if( rc != SQLITE_OK ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "In SetFeature(): sqlite3_prepare(%s):\n %s", + osCommand.c_str(), sqlite3_errmsg(hDB) ); + + return OGRERR_FAILURE; + } + +/* -------------------------------------------------------------------- */ +/* Bind values. */ +/* -------------------------------------------------------------------- */ + OGRErr eErr = BindValues( poFeature, hUpdateStmt, TRUE ); + if (eErr != OGRERR_NONE) + { + sqlite3_finalize( hUpdateStmt ); + return eErr; + } + +/* -------------------------------------------------------------------- */ +/* Execute the update. */ +/* -------------------------------------------------------------------- */ + rc = sqlite3_step( hUpdateStmt ); + + if( rc != SQLITE_OK && rc != SQLITE_DONE ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "sqlite3_step() failed:\n %s", + sqlite3_errmsg(hDB) ); + + sqlite3_finalize( hUpdateStmt ); + return OGRERR_FAILURE; + } + + sqlite3_finalize( hUpdateStmt ); + + OGRGeometry *poGeom = poFeature->GetGeometryRef(); + if( bCachedExtentIsValid && + poGeom != NULL && !poGeom->IsEmpty() ) + { + OGREnvelope sGeomEnvelope; + poGeom->getEnvelope(&sGeomEnvelope); + oCachedExtent.Merge(sGeomEnvelope); + } + bStatisticsNeedsToBeFlushed = TRUE; + + return OGRERR_NONE; +} + +/************************************************************************/ +/* CreateFeature() */ +/************************************************************************/ + +OGRErr OGRSQLiteViewLayer::CreateFeature( OGRFeature *poFeature ) + +{ + sqlite3 *hDB = poDS->GetDB(); + CPLString osCommand; + CPLString osValues; + int bNeedComma = FALSE; + + if (!bTriggerInsert) + return OGRERR_FAILURE; // mj10777: no trigger for 'INSTEAD OF INSERT' + + if (HasLayerDefnError()) + return OGRERR_FAILURE; + + if (!poDS->GetUpdate()) + { + CPLError( CE_Failure, CPLE_NotSupported, + UNSUPPORTED_OP_READ_ONLY, + "CreateFeature"); + return OGRERR_FAILURE; + } + + ResetReading(); + +/* -------------------------------------------------------------------- */ +/* Form the INSERT command. */ +/* -------------------------------------------------------------------- */ + osCommand += CPLSPrintf( "INSERT INTO '%s' (", pszEscapedTableName ); + +/* -------------------------------------------------------------------- */ +/* Add FID if we have a cleartext FID column. */ +/* -------------------------------------------------------------------- */ + if( pszFIDColumn != NULL // && !EQUAL(pszFIDColumn,"OGC_FID") + && poFeature->GetFID() != OGRNullFID ) + { + osCommand += "\""; + osCommand += OGRSQLiteEscapeName(pszFIDColumn); + osCommand += "\""; + + osValues += CPLSPrintf( "%ld", poFeature->GetFID() ); + bNeedComma = TRUE; + } + +/* -------------------------------------------------------------------- */ +/* Add geometry. */ +/* -------------------------------------------------------------------- */ + OGRGeometry *poGeom = poFeature->GetGeometryRef(); + + if( poFeatureDefn->GetGeomFieldCount() != 0 && + poGeom != NULL && + eGeomFormat != OSGF_FGF ) + { + + if( bNeedComma ) + { + osCommand += ","; + osValues += ","; + } + + osCommand += "\""; + osCommand += OGRSQLiteEscapeName(pszGeomCol); + osCommand += "\""; + + osValues += "?"; + + bNeedComma = TRUE; + } + +/* -------------------------------------------------------------------- */ +/* Add field values. */ +/* -------------------------------------------------------------------- */ + int iField; + int nFieldCount = poFeatureDefn->GetFieldCount(); + + for( iField = 0; iField < nFieldCount; iField++ ) + { + if( !poFeature->IsFieldSet( iField ) ) + continue; + + if( bNeedComma ) + { + osCommand += ","; + osValues += ","; + } + + osCommand += "\""; + osCommand += OGRSQLiteEscapeName(poFeatureDefn->GetFieldDefn(iField)->GetNameRef()); + osCommand += "\""; + + osValues += "?"; + + bNeedComma = TRUE; + } + +/* -------------------------------------------------------------------- */ +/* Merge final command. */ +/* -------------------------------------------------------------------- */ + osCommand += ") VALUES ("; + osCommand += osValues; + osCommand += ")"; + + if (bNeedComma == FALSE) + osCommand = CPLSPrintf( "INSERT INTO '%s' DEFAULT VALUES", pszEscapedTableName ); + +/* -------------------------------------------------------------------- */ +/* Prepare the statement. */ +/* -------------------------------------------------------------------- */ + int rc; + + if (hInsertStmt == NULL || + osCommand != osLastInsertStmt) + { + #ifdef DEBUG + CPLDebug( "OGR_SQLITE", "prepare(%s)", osCommand.c_str() ); + #endif + + ClearInsertStmt(); + osLastInsertStmt = osCommand; + +#ifdef HAVE_SQLITE3_PREPARE_V2 + rc = sqlite3_prepare_v2( hDB, osCommand, -1, &hInsertStmt, NULL ); +#else + rc = sqlite3_prepare( hDB, osCommand, -1, &hInsertStmt, NULL ); +#endif + if( rc != SQLITE_OK ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "In CreateFeature(): sqlite3_prepare(%s):\n %s", + osCommand.c_str(), sqlite3_errmsg(hDB) ); + + ClearInsertStmt(); + return OGRERR_FAILURE; + } + } + +/* -------------------------------------------------------------------- */ +/* Bind values. */ +/* -------------------------------------------------------------------- */ + OGRErr eErr = BindValues( poFeature, hInsertStmt, FALSE ); + if (eErr != OGRERR_NONE) + { + sqlite3_reset( hInsertStmt ); + return eErr; + } + +/* -------------------------------------------------------------------- */ +/* Execute the insert. */ +/* -------------------------------------------------------------------- */ + rc = sqlite3_step( hInsertStmt ); + + if( rc != SQLITE_OK && rc != SQLITE_DONE ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "sqlite3_step() failed:\n %s (%d)", + sqlite3_errmsg(hDB), rc ); + sqlite3_reset( hInsertStmt ); + return OGRERR_FAILURE; + } + +/* -------------------------------------------------------------------- */ +/* Capture the FID/rowid. */ +/* -------------------------------------------------------------------- */ + const sqlite_int64 nFID = sqlite3_last_insert_rowid( hDB ); + if(nFID > 0) + { + poFeature->SetFID( (long)nFID ); /* Possible truncation if nFID is 64bit */ + } + + sqlite3_reset( hInsertStmt ); + + if( (bCachedExtentIsValid || nFeatureCount == 0) && + poGeom != NULL && !poGeom->IsEmpty() ) + { + OGREnvelope sGeomEnvelope; + poGeom->getEnvelope(&sGeomEnvelope); + oCachedExtent.Merge(sGeomEnvelope); + bCachedExtentIsValid = TRUE; + bStatisticsNeedsToBeFlushed = TRUE; + } + if( nFeatureCount >= 0 ) + { + bStatisticsNeedsToBeFlushed = TRUE; + nFeatureCount ++; + } + + return OGRERR_NONE; +} + +/************************************************************************/ +/* DeleteFeature() */ +/************************************************************************/ + +OGRErr OGRSQLiteViewLayer::DeleteFeature( long nFID ) + +{ + CPLString osSQL; + int rc; + char *pszErrMsg = NULL; + + if (!bTriggerDelete) + return OGRERR_FAILURE; // mj10777: no trigger for 'INSTEAD OF DELETE' + + if (HasLayerDefnError()) + return OGRERR_FAILURE; + + if( pszFIDColumn == NULL ) + { + CPLError( CE_Failure, CPLE_NotSupported, + "Can't delete feature on a layer without FID column."); + return OGRERR_FAILURE; + } + + if (!poDS->GetUpdate()) + { + CPLError( CE_Failure, CPLE_NotSupported, + UNSUPPORTED_OP_READ_ONLY, + "DeleteFeature"); + return OGRERR_FAILURE; + } + + ResetReading(); + + osSQL.Printf( "DELETE FROM '%s' WHERE \"%s\" = %ld", + pszEscapedTableName, + OGRSQLiteEscapeName(pszFIDColumn).c_str(), nFID ); + + CPLDebug( "OGR_SQLITE", "exec(%s)", osSQL.c_str() ); + + rc = sqlite3_exec( poDS->GetDB(), osSQL, NULL, NULL, &pszErrMsg ); + if( rc != SQLITE_OK ) + { + CPLError( CE_Failure, CPLE_AppDefined, + "In DeleteFeature(): sqlite3_exec(%s):\n %s", + osSQL.c_str(), pszErrMsg ); + sqlite3_free( pszErrMsg ); + return OGRERR_FAILURE; + } + + int nChanged = sqlite3_changes( poDS->GetDB() ); + + if( nChanged == 1 ) + { + bCachedExtentIsValid = FALSE; + nFeatureCount --; + bStatisticsNeedsToBeFlushed = TRUE; + } + + return OGRERR_NONE; +} + +/************************************************************************/ /* ResetStatement() */ /************************************************************************/ @@ -539,6 +1242,31 @@ else if (EQUAL(pszCap,OLCFastSpatialFilter)) return bHasSpatialIndex; + else if( EQUAL(pszCap,OLCSequentialWrite) ) + { // mj10777: trigger for 'INSTEAD OF INSERT' + return bTriggerInsert; + } + else if( EQUAL(pszCap,OLCRandomWrite) ) + { // mj10777: trigger for 'INSTEAD OF UPDATE' + return bTriggerUpdate; + } + else if( EQUAL(pszCap,OLCDeleteFeature) ) + { // mj10777: trigger for 'INSTEAD OF DELETE' + return bTriggerDelete; + } + // mj10777: for views always FALSE + else if( EQUAL(pszCap,OLCCreateField) ) + return FALSE; + + else if( EQUAL(pszCap,OLCDeleteField) ) + return FALSE; + + else if( EQUAL(pszCap,OLCAlterFieldDefn) ) + return FALSE; + + else if( EQUAL(pszCap,OLCReorderFields) ) + return FALSE; + else return OGRSQLiteLayer::TestCapability( pszCap ); }