Repository: ckan/ckan

Issue:
Exception when deleting resource if datastore table should exist but does not
**2.8.4**

**Describe the bug**
If for whatever reason, you end up with a resource for which datastore_active is set in the resource extras, but the datastore table does not actually exist, an exception is thown when trying to delete this resource.

**Steps to reproduce**
1. Create a resource and make sure data is uploaded to the datastore
2. Manually delete the database table of this resource from the database
3. Try to delete this resource via the ckan UI
4. An exception is thrown

**Expected behavior**
Before deleting, check whether the datastore table actually exists. If it doesn't exist, just skip the delete step. Better than throwing an exception.

**Additional details**
Not sure how I managed to get into this inconsistent state. Might not even be CKAN's fault since we had some issues with our persistence infrastructure/volumes.

Stack trace here:
```
File '/srv/app/src/ckan/ckan/controllers/package.py', line 1175 in resource_delete
  get_action('resource_delete')(context, {'id': resource_id})
File '/srv/app/src/ckan/ckan/logic/__init__.py', line 466 in wrapped
  result = _action(context, data_dict, **kw)
File '/srv/app/src/ckan/ckan/logic/action/delete.py', line 204 in resource_delete
  plugin.after_delete(context, pkg_dict.get('resources', []))
File '/srv/app/src/ckan/ckanext/datastore/plugin.py', line 161 in after_delete
  'resource_id': res.id,
File '/srv/app/src/ckan/ckanext/datastore/backend/postgres.py', line 1720 in delete
  data_dict['resource_id'])
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py', line 939 in execute
  return self._execute_text(object, multiparams, params)
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py', line 1097 in _execute_text
  statement, parameters
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py', line 1189 in _execute_context
  context)
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py', line 1402 in _handle_dbapi_exception
  exc_info
File '/usr/lib/python2.7/site-packages/sqlalchemy/util/compat.py', line 203 in raise_from_cause
  reraise(type(exception), exception, tb=exc_tb, cause=cause)
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/base.py', line 1182 in _execute_context
  context)
File '/usr/lib/python2.7/site-packages/sqlalchemy/engine/default.py', line 470 in do_execute
  cursor.execute(statement, parameters)
ProgrammingError: (psycopg2.ProgrammingError) table "f03c4532-bc47-4ca0-bf73-f96e42082f49" does not exist
 [SQL: 'DROP TABLE "f03c4532-bc47-4ca0-bf73-f96e42082f49" CASCADE']
```

I will provide a pull request.


Discussion:

Resolving patch:
diff --git a/ckanext/datastore/plugin.py b/ckanext/datastore/plugin.py
--- a/ckanext/datastore/plugin.py
+++ b/ckanext/datastore/plugin.py
@@ -145,9 +145,10 @@ def after_delete(self, context, resources):
             if res.extras.get('datastore_active') is True]
 
         for res in deleted:
-            self.backend.delete(context, {
-                'resource_id': res.id,
-            })
+            if self.backend.resource_exists(res.id):
+                self.backend.delete(context, {
+                    'resource_id': res.id,
+                })
             res.extras['datastore_active'] = False
             res_query.filter_by(id=res.id).update(
                 {'extras': res.extras}, synchronize_session=False)


Test patch: