prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Datastore dump results are not the same as data in database
  ### CKAN Version if known (or site URL)
  2.7.2
  
  ### Please describe the expected behaviour
  Downloaded dataset is not consistent with the actual data! 
  
  ### Please describe the actual behaviour
  We've upserted data using datastore api. The data is shown correctly in data explorer, Table view, API call or even querying postgres, But the data in downloaded csv file is different! Total number of records are the same but in csv we have random number of duplicates and missing data.
  
  ### What steps can be taken to reproduce the issue? 
  Upsert data using API. Download the CSV file using URL. Filter and compare downloaded data and data shown in data explorer or table view.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `ckanext/datastore/controller.py`
  Content:
  ```
  1 # encoding: utf-8
  2 
  3 from ckan.plugins.toolkit import (
  4     Invalid,
  5     ObjectNotFound,
  6     NotAuthorized,
  7     get_action,
  8     get_validator,
  9     _,
  10     request,
  11     response,
  12     BaseController,
  13     abort,
  14     render,
  15     c,
  16     h,
  17 )
  18 from ckanext.datastore.writer import (
  19     csv_writer,
  20     tsv_writer,
  21     json_writer,
  22     xml_writer,
  23 )
  24 from ckan.logic import (
  25     tuplize_dict,
  26     parse_params,
  27 )
  28 import ckan.lib.navl.dictization_functions as dict_fns
  29 
  30 from itertools import izip_longest
  31 
  32 int_validator = get_validator('int_validator')
  33 boolean_validator = get_validator('boolean_validator')
  34 
  35 DUMP_FORMATS = 'csv', 'tsv', 'json', 'xml'
  36 PAGINATE_BY = 32000
  37 
  38 
  39 class DatastoreController(BaseController):
  40     def dump(self, resource_id):
  41         try:
  42             offset = int_validator(request.GET.get('offset', 0), {})
  43         except Invalid as e:
  44             abort(400, u'offset: ' + e.error)
  45         try:
  46             limit = int_validator(request.GET.get('limit'), {})
  47         except Invalid as e:
  48             abort(400, u'limit: ' + e.error)
  49         bom = boolean_validator(request.GET.get('bom'), {})
  50         fmt = request.GET.get('format', 'csv')
  51 
  52         if fmt not in DUMP_FORMATS:
  53             abort(400, _(
  54                 u'format: must be one of %s') % u', '.join(DUMP_FORMATS))
  55 
  56         try:
  57             dump_to(
  58                 resource_id,
  59                 response,
  60                 fmt=fmt,
  61                 offset=offset,
  62                 limit=limit,
  63                 options={u'bom': bom})
  64         except ObjectNotFound:
  65             abort(404, _('DataStore resource not found'))
  66 
  67     def dictionary(self, id, resource_id):
  68         u'''data dictionary view: show/edit field labels and descriptions'''
  69 
  70         try:
  71             # resource_edit_base template uses these
  72             c.pkg_dict = get_action('package_show')(
  73                 None, {'id': id})
  74             c.resource = get_action('resource_show')(
  75                 None, {'id': resource_id})
  76             rec = get_action('datastore_search')(None, {
  77                 'resource_id': resource_id,
  78                 'limit': 0})
  79         except (ObjectNotFound, NotAuthorized):
  80             abort(404, _('Resource not found'))
  81 
  82         fields = [f for f in rec['fields'] if not f['id'].startswith('_')]
  83 
  84         if request.method == 'POST':
  85             data = dict_fns.unflatten(tuplize_dict(parse_params(
  86                 request.params)))
  87             info = data.get(u'info')
  88             if not isinstance(info, list):
  89                 info = []
  90             info = info[:len(fields)]
  91 
  92             get_action('datastore_create')(None, {
  93                 'resource_id': resource_id,
  94                 'force': True,
  95                 'fields': [{
  96                     'id': f['id'],
  97                     'type': f['type'],
  98                     'info': fi if isinstance(fi, dict) else {}
  99                     } for f, fi in izip_longest(fields, info)]})
  100 
  101             h.flash_success(_('Data Dictionary saved. Any type overrides will '
  102                               'take effect when the resource is next uploaded '
  103                               'to DataStore'))
  104             h.redirect_to(
  105                 controller='ckanext.datastore.controller:DatastoreController',
  106                 action='dictionary',
  107                 id=id,
  108                 resource_id=resource_id)
  109 
  110         return render(
  111             'datastore/dictionary.html',
  112             extra_vars={'fields': fields})
  113 
  114 
  115 def dump_to(resource_id, output, fmt, offset, limit, options):
  116     if fmt == 'csv':
  117         writer_factory = csv_writer
  118         records_format = 'csv'
  119     elif fmt == 'tsv':
  120         writer_factory = tsv_writer
  121         records_format = 'tsv'
  122     elif fmt == 'json':
  123         writer_factory = json_writer
  124         records_format = 'lists'
  125     elif fmt == 'xml':
  126         writer_factory = xml_writer
  127         records_format = 'objects'
  128 
  129     def start_writer(fields):
  130         bom = options.get(u'bom', False)
  131         return writer_factory(output, fields, resource_id, bom)
  132 
  133     def result_page(offs, lim):
  134         return get_action('datastore_search')(None, {
  135             'resource_id': resource_id,
  136             'limit':
  137                 PAGINATE_BY if limit is None
  138                 else min(PAGINATE_BY, lim),
  139             'offset': offs,
  140             'records_format': records_format,
  141             'include_total': 'false',  # XXX: default() is broken
  142         })
  143 
  144     result = result_page(offset, limit)
  145 
  146     with start_writer(result['fields']) as wr:
  147         while True:
  148             if limit is not None and limit <= 0:
  149                 break
  150 
  151             records = result['records']
  152 
  153             wr.write_records(records)
  154 
  155             if records_format == 'objects' or records_format == 'lists':
  156                 if len(records) < PAGINATE_BY:
  157                     break
  158             elif not records:
  159                 break
  160 
  161             offset += PAGINATE_BY
  162             if limit is not None:
  163                 limit -= PAGINATE_BY
  164                 if limit <= 0:
  165                     break
  166 
  167             result = result_page(offset, limit)
  168
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/ckanext/datastore/controller.py b/ckanext/datastore/controller.py
  --- a/ckanext/datastore/controller.py
  +++ b/ckanext/datastore/controller.py
  @@ -137,6 +137,7 @@
                   PAGINATE_BY if limit is None
                   else min(PAGINATE_BY, lim),
               'offset': offs,
  +            'sort': '_id',
               'records_format': records_format,
               'include_total': 'false',  # XXX: default() is broken
           })
  
verification_info: {"golden_diff": "diff --git a/ckanext/datastore/controller.py b/ckanext/datastore/controller.py\n--- a/ckanext/datastore/controller.py\n+++ b/ckanext/datastore/controller.py\n@@ -137,6 +137,7 @@\n                 PAGINATE_BY if limit is None\n                 else min(PAGINATE_BY, lim),\n             'offset': offs,\n+            'sort': '_id',\n             'records_format': records_format,\n             'include_total': 'false',  # XXX: default() is broken\n         })\n", "issue": "Datastore dump results are not the same as data in database\n### CKAN Version if known (or site URL)\r\n2.7.2\r\n\r\n### Please describe the expected behaviour\r\nDownloaded dataset is not consistent with the actual data! \r\n\r\n### Please describe the actual behaviour\r\nWe've upserted data using datastore api. The data is shown correctly in data explorer, Table view, API call or even querying postgres, But the data in downloaded csv file is different! Total number of records are the same but in csv we have random number of duplicates and missing data.\r\n\r\n### What steps can be taken to reproduce the issue? \r\nUpsert data using API. Download the CSV file using URL. Filter and compare downloaded data and data shown in data explorer or table view.\n", "before_files": [{"content": "# encoding: utf-8\n\nfrom ckan.plugins.toolkit import (\n    Invalid,\n    ObjectNotFound,\n    NotAuthorized,\n    get_action,\n    get_validator,\n    _,\n    request,\n    response,\n    BaseController,\n    abort,\n    render,\n    c,\n    h,\n)\nfrom ckanext.datastore.writer import (\n    csv_writer,\n    tsv_writer,\n    json_writer,\n    xml_writer,\n)\nfrom ckan.logic import (\n    tuplize_dict,\n    parse_params,\n)\nimport ckan.lib.navl.dictization_functions as dict_fns\n\nfrom itertools import izip_longest\n\nint_validator = get_validator('int_validator')\nboolean_validator = get_validator('boolean_validator')\n\nDUMP_FORMATS = 'csv', 'tsv', 'json', 'xml'\nPAGINATE_BY = 32000\n\n\nclass DatastoreController(BaseController):\n    def dump(self, resource_id):\n        try:\n            offset = int_validator(request.GET.get('offset', 0), {})\n        except Invalid as e:\n            abort(400, u'offset: ' + e.error)\n        try:\n            limit = int_validator(request.GET.get('limit'), {})\n        except Invalid as e:\n            abort(400, u'limit: ' + e.error)\n        bom = boolean_validator(request.GET.get('bom'), {})\n        fmt = request.GET.get('format', 'csv')\n\n        if fmt not in DUMP_FORMATS:\n            abort(400, _(\n                u'format: must be one of %s') % u', '.join(DUMP_FORMATS))\n\n        try:\n            dump_to(\n                resource_id,\n                response,\n                fmt=fmt,\n                offset=offset,\n                limit=limit,\n                options={u'bom': bom})\n        except ObjectNotFound:\n            abort(404, _('DataStore resource not found'))\n\n    def dictionary(self, id, resource_id):\n        u'''data dictionary view: show/edit field labels and descriptions'''\n\n        try:\n            # resource_edit_base template uses these\n            c.pkg_dict = get_action('package_show')(\n                None, {'id': id})\n            c.resource = get_action('resource_show')(\n                None, {'id': resource_id})\n            rec = get_action('datastore_search')(None, {\n                'resource_id': resource_id,\n                'limit': 0})\n        except (ObjectNotFound, NotAuthorized):\n            abort(404, _('Resource not found'))\n\n        fields = [f for f in rec['fields'] if not f['id'].startswith('_')]\n\n        if request.method == 'POST':\n            data = dict_fns.unflatten(tuplize_dict(parse_params(\n                request.params)))\n            info = data.get(u'info')\n            if not isinstance(info, list):\n                info = []\n            info = info[:len(fields)]\n\n            get_action('datastore_create')(None, {\n                'resource_id': resource_id,\n                'force': True,\n                'fields': [{\n                    'id': f['id'],\n                    'type': f['type'],\n                    'info': fi if isinstance(fi, dict) else {}\n                    } for f, fi in izip_longest(fields, info)]})\n\n            h.flash_success(_('Data Dictionary saved. Any type overrides will '\n                              'take effect when the resource is next uploaded '\n                              'to DataStore'))\n            h.redirect_to(\n                controller='ckanext.datastore.controller:DatastoreController',\n                action='dictionary',\n                id=id,\n                resource_id=resource_id)\n\n        return render(\n            'datastore/dictionary.html',\n            extra_vars={'fields': fields})\n\n\ndef dump_to(resource_id, output, fmt, offset, limit, options):\n    if fmt == 'csv':\n        writer_factory = csv_writer\n        records_format = 'csv'\n    elif fmt == 'tsv':\n        writer_factory = tsv_writer\n        records_format = 'tsv'\n    elif fmt == 'json':\n        writer_factory = json_writer\n        records_format = 'lists'\n    elif fmt == 'xml':\n        writer_factory = xml_writer\n        records_format = 'objects'\n\n    def start_writer(fields):\n        bom = options.get(u'bom', False)\n        return writer_factory(output, fields, resource_id, bom)\n\n    def result_page(offs, lim):\n        return get_action('datastore_search')(None, {\n            'resource_id': resource_id,\n            'limit':\n                PAGINATE_BY if limit is None\n                else min(PAGINATE_BY, lim),\n            'offset': offs,\n            'records_format': records_format,\n            'include_total': 'false',  # XXX: default() is broken\n        })\n\n    result = result_page(offset, limit)\n\n    with start_writer(result['fields']) as wr:\n        while True:\n            if limit is not None and limit <= 0:\n                break\n\n            records = result['records']\n\n            wr.write_records(records)\n\n            if records_format == 'objects' or records_format == 'lists':\n                if len(records) < PAGINATE_BY:\n                    break\n            elif not records:\n                break\n\n            offset += PAGINATE_BY\n            if limit is not None:\n                limit -= PAGINATE_BY\n                if limit <= 0:\n                    break\n\n            result = result_page(offset, limit)\n", "path": "ckanext/datastore/controller.py"}], "after_files": [{"content": "# encoding: utf-8\n\nfrom ckan.plugins.toolkit import (\n    Invalid,\n    ObjectNotFound,\n    NotAuthorized,\n    get_action,\n    get_validator,\n    _,\n    request,\n    response,\n    BaseController,\n    abort,\n    render,\n    c,\n    h,\n)\nfrom ckanext.datastore.writer import (\n    csv_writer,\n    tsv_writer,\n    json_writer,\n    xml_writer,\n)\nfrom ckan.logic import (\n    tuplize_dict,\n    parse_params,\n)\nimport ckan.lib.navl.dictization_functions as dict_fns\n\nfrom itertools import izip_longest\n\nint_validator = get_validator('int_validator')\nboolean_validator = get_validator('boolean_validator')\n\nDUMP_FORMATS = 'csv', 'tsv', 'json', 'xml'\nPAGINATE_BY = 32000\n\n\nclass DatastoreController(BaseController):\n    def dump(self, resource_id):\n        try:\n            offset = int_validator(request.GET.get('offset', 0), {})\n        except Invalid as e:\n            abort(400, u'offset: ' + e.error)\n        try:\n            limit = int_validator(request.GET.get('limit'), {})\n        except Invalid as e:\n            abort(400, u'limit: ' + e.error)\n        bom = boolean_validator(request.GET.get('bom'), {})\n        fmt = request.GET.get('format', 'csv')\n\n        if fmt not in DUMP_FORMATS:\n            abort(400, _(\n                u'format: must be one of %s') % u', '.join(DUMP_FORMATS))\n\n        try:\n            dump_to(\n                resource_id,\n                response,\n                fmt=fmt,\n                offset=offset,\n                limit=limit,\n                options={u'bom': bom})\n        except ObjectNotFound:\n            abort(404, _('DataStore resource not found'))\n\n    def dictionary(self, id, resource_id):\n        u'''data dictionary view: show/edit field labels and descriptions'''\n\n        try:\n            # resource_edit_base template uses these\n            c.pkg_dict = get_action('package_show')(\n                None, {'id': id})\n            c.resource = get_action('resource_show')(\n                None, {'id': resource_id})\n            rec = get_action('datastore_search')(None, {\n                'resource_id': resource_id,\n                'limit': 0})\n        except (ObjectNotFound, NotAuthorized):\n            abort(404, _('Resource not found'))\n\n        fields = [f for f in rec['fields'] if not f['id'].startswith('_')]\n\n        if request.method == 'POST':\n            data = dict_fns.unflatten(tuplize_dict(parse_params(\n                request.params)))\n            info = data.get(u'info')\n            if not isinstance(info, list):\n                info = []\n            info = info[:len(fields)]\n\n            get_action('datastore_create')(None, {\n                'resource_id': resource_id,\n                'force': True,\n                'fields': [{\n                    'id': f['id'],\n                    'type': f['type'],\n                    'info': fi if isinstance(fi, dict) else {}\n                    } for f, fi in izip_longest(fields, info)]})\n\n            h.flash_success(_('Data Dictionary saved. Any type overrides will '\n                              'take effect when the resource is next uploaded '\n                              'to DataStore'))\n            h.redirect_to(\n                controller='ckanext.datastore.controller:DatastoreController',\n                action='dictionary',\n                id=id,\n                resource_id=resource_id)\n\n        return render(\n            'datastore/dictionary.html',\n            extra_vars={'fields': fields})\n\n\ndef dump_to(resource_id, output, fmt, offset, limit, options):\n    if fmt == 'csv':\n        writer_factory = csv_writer\n        records_format = 'csv'\n    elif fmt == 'tsv':\n        writer_factory = tsv_writer\n        records_format = 'tsv'\n    elif fmt == 'json':\n        writer_factory = json_writer\n        records_format = 'lists'\n    elif fmt == 'xml':\n        writer_factory = xml_writer\n        records_format = 'objects'\n\n    def start_writer(fields):\n        bom = options.get(u'bom', False)\n        return writer_factory(output, fields, resource_id, bom)\n\n    def result_page(offs, lim):\n        return get_action('datastore_search')(None, {\n            'resource_id': resource_id,\n            'limit':\n                PAGINATE_BY if limit is None\n                else min(PAGINATE_BY, lim),\n            'offset': offs,\n            'sort': '_id',\n            'records_format': records_format,\n            'include_total': 'false',  # XXX: default() is broken\n        })\n\n    result = result_page(offset, limit)\n\n    with start_writer(result['fields']) as wr:\n        while True:\n            if limit is not None and limit <= 0:\n                break\n\n            records = result['records']\n\n            wr.write_records(records)\n\n            if records_format == 'objects' or records_format == 'lists':\n                if len(records) < PAGINATE_BY:\n                    break\n            elif not records:\n                break\n\n            offset += PAGINATE_BY\n            if limit is not None:\n                limit -= PAGINATE_BY\n                if limit <= 0:\n                    break\n\n            result = result_page(offset, limit)\n", "path": "ckanext/datastore/controller.py"}]}