| Ticket Hash: | 597fce55f2884668a24b591840162ffebda390e1 | |||
| Title: | Adapting addVectorLayerAuth to look for triggers for SpatialViews | |||
| Status: | Closed | Type: | Feature_Request | |
| Severity: | Important | Priority: | Immediate | |
| Subsystem: | Resolution: | Fixed | ||
| Last Modified: | 2017-05-30 09:59:19 | |||
| Version Found In: | 4.5.0dev | |||
| User Comments: | ||||
| 
mj10777 added on 2017-05-12 09:02:06:
 Providers have problems in supporting writable SpatialViews properly 
 QGis does this incorrectly (looks if a trigger exists, but not what type) Since gaiaGetVectorLayersList collects capability information about all Vector Layers, information about what a writable SpatialView is capable of, should be included. typedef struct gaiaLayerAuthInfos after IsReadOnly: /** Flag indicating if the Capabilities of the SpatialView supports Inserting: TRUE or FALSE */ int HasTriggerInsert; /** Flag indicating if the Capabilities of the SpatialView supports Updating: TRUE or FALSE */ int HasTriggerUpdate; /** Flag indicating if the Capabilities of the SpatialView supports Deleting: TRUE or FALSE */ int HasTriggerDelete; addVectorLayerAuth Add 'sqlite3 * handle,' to function parameters, which is called from: 
 get_table_auth_legacy after setting of IsReadOnly: 
  auth->HasTriggerInsert = 0;
  auth->HasTriggerUpdate = 0;
  auth->HasTriggerDelete = 0;
  if ((lyr->LayerType == GAIA_VECTOR_VIEW) && (!auth->IsReadOnly))
  {
   auth->IsReadOnly = 1; // Claims to be a Writable SpatialView, we shall see ...
   sql =
    sqlite3_mprintf("SELECT "
     "(SELECT Exists(SELECT rootpage FROM  sqlite_master WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND (instr(upper(sql),'INSTEAD OF INSERT') > 0)))), "
     "(SELECT Exists(SELECT rootpage FROM  sqlite_master WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND (instr(upper(sql),'INSTEAD OF UPDATE') > 0)))), "
     "(SELECT Exists(SELECT rootpage FROM  sqlite_master WHERE (type = 'trigger' AND Lower(tbl_name) = Lower(%Q) AND (instr(upper(sql),'INSTEAD OF DELETE') > 0))))"
     , table_name,table_name,table_name);
   ret = sqlite3_prepare_v2 (handle, sql, strlen (sql), &stmt, NULL);
   sqlite3_free (sql);
   if (ret == SQLITE_OK)
   {
    while ( sqlite3_step( stmt ) == SQLITE_ROW )
    {
     if ( sqlite3_column_type( stmt, 0 ) != SQLITE_NULL )
     {
      if ( sqlite3_column_int( stmt, 0 ) == 1 )
      {
       auth->HasTriggerInsert = 1;
       auth->IsReadOnly = 0; // Yes, this could be a functional Writable SpatialView
      }
     }
     if ( sqlite3_column_type( stmt, 1 ) != SQLITE_NULL )
     {
      if ( sqlite3_column_int( stmt, 1 ) == 1 )
      {
       auth->HasTriggerUpdate = 1;
       auth->IsReadOnly = 0; // Yes, this could be a functional Writable SpatialView
      }
     }
     if ( sqlite3_column_type( stmt, 2 ) != SQLITE_NULL )
     {
      if ( sqlite3_column_int( stmt, 2 ) == 1 )
      {
       auth->HasTriggerDelete = 1;
       auth->IsReadOnly = 0; // Yes, this could be a functional Writable SpatialView
      }
     }
    }
    ret = sqlite3_finalize (stmt);
   }
  }
Should deal with this matter in a way that Providers could rely upon (As always with no guarantee that the trigger works correctly). sandro added on 2017-05-13 12:07:46: patch accepted and immediately available from the Fossil repo. mj10777 added on 2017-05-13 14:49:32: 2 corrections: 
 the && should be changed to ||, because if (at least) one is true - then the view is writable. 
    if (*has_trigger_delete && *has_trigger_update && *has_trigger_delete)
    if (*has_trigger_insert || *has_trigger_update || *has_trigger_delete)
sandro added on 2017-05-13 15:41:53: Yes I agree, a View supporting at least one between INSERT, UPDATE or DELETE technically speaking is a Writable View. Anyway this patch is mainly intended to support the QGIS own data provider, and I easily imagine that in this specific context a set of Triggers only implementing an incomplete write support (i.e. INSERT and/or UPDATE but no DELETE) will very probably cause havoc. mj10777 added on 2017-05-13 15:55:38: if readonly is TRUE, no further checking is done. if readonly is FALSE, the 3 settings are checked and the appropriate Capabilities set: 
  if ( mViewBased  &&  !mReadOnly )
  {
    // enabling editing for Spatialview when the corresponding TRIGGER exists
    if ( mTriggerDelete )
    {
      mEnabledCapabilities |= QgsVectorDataProvider::DeleteFeatures | QgsVectorDataProvider::FastTruncate;
    }
    if ( mTriggerUpdate )
    {
      mEnabledCapabilities |= QgsVectorDataProvider::ChangeGeometries;
      mEnabledCapabilities |= QgsVectorDataProvider::ChangeAttributeValues;
    }
    if ( mTriggerInsert )
    {
      mEnabledCapabilities |= QgsVectorDataProvider::AddFeatures;
      mEnabledCapabilities |= QgsVectorDataProvider::AddAttributes;
      mEnabledCapabilities |= QgsVectorDataProvider::CreateAttributeIndex;
    }
  }
In this way, when mTriggerInsert == FALSE, the gui will not allow new geometries to be created
 sandro added on 2017-05-14 09:27:03: all right, this definitely clarifies what is the implementation expected by the QGIS data provider. mj10777 added on 2017-05-26 09:18:41: For SpatialViews, addVectorLayerAuth is never called 
 
 Legacy: SpatialViews are not contained in geometry_columns_auth Legacy: 
 
 gaiaGetVectorLayersList_v4: 
 
 API-Documentation should be added for gaiaGetVectorLayersList 
 
 sandro added on 2017-05-30 09:59:19: supposed to be fixed by the latest commit. please test if it now correctly works.  | ||||