prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  empty strings stored as NULL in db
  https://groups.google.com/forum/#!topic/web2py/IYzhhd3eKXQ
  
  
  </issue>
  <code>
  [start of gluon/dal.py]
  1 #!/usr/bin/env python
  2 # -*- coding: utf-8 -*-
  3 
  4 """
  5 | This file is part of the web2py Web Framework
  6 | Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>
  7 | License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)
  8 
  9 Takes care of adapting pyDAL to web2py's needs
  10 -----------------------------------------------
  11 """
  12 
  13 from pydal import DAL as DAL
  14 from pydal import Field
  15 from pydal.objects import Row, Rows, Table, Query, Set, Expression
  16 from pydal import SQLCustomType, geoPoint, geoLine, geoPolygon
  17 
  18 
  19 def _default_validators(db, field):
  20     """
  21     Field type validation, using web2py's validators mechanism.
  22 
  23     makes sure the content of a field is in line with the declared
  24     fieldtype
  25     """
  26     from gluon import validators
  27     field_type, field_length = field.type, field.length
  28     requires = []
  29 
  30     if field_type in (('string', 'text', 'password')):
  31         requires.append(validators.IS_LENGTH(field_length))
  32     elif field_type == 'json':
  33         requires.append(validators.IS_EMPTY_OR(validators.IS_JSON()))
  34     elif field_type == 'double' or field_type == 'float':
  35         requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100))
  36     elif field_type == 'integer':
  37         requires.append(validators.IS_INT_IN_RANGE(-2**31, 2**31))
  38     elif field_type == 'bigint':
  39         requires.append(validators.IS_INT_IN_RANGE(-2**63, 2**63))
  40     elif field_type.startswith('decimal'):
  41         requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10))
  42     elif field_type == 'date':
  43         requires.append(validators.IS_DATE())
  44     elif field_type == 'time':
  45         requires.append(validators.IS_TIME())
  46     elif field_type == 'datetime':
  47         requires.append(validators.IS_DATETIME())
  48     elif db and field_type.startswith('reference') and \
  49             field_type.find('.') < 0 and \
  50             field_type[10:] in db.tables:
  51         referenced = db[field_type[10:]]
  52         if hasattr(referenced, '_format') and referenced._format:
  53             requires = validators.IS_IN_DB(db, referenced._id,
  54                                            referenced._format)
  55             if field.unique:
  56                 requires._and = validators.IS_NOT_IN_DB(db, field)
  57             if field.tablename == field_type[10:]:
  58                 return validators.IS_EMPTY_OR(requires)
  59             return requires
  60     elif db and field_type.startswith('list:reference') and \
  61             field_type.find('.') < 0 and \
  62             field_type[15:] in db.tables:
  63         referenced = db[field_type[15:]]
  64         if hasattr(referenced, '_format') and referenced._format:
  65             requires = validators.IS_IN_DB(db, referenced._id,
  66                                            referenced._format, multiple=True)
  67         else:
  68             requires = validators.IS_IN_DB(db, referenced._id,
  69                                            multiple=True)
  70         if field.unique:
  71             requires._and = validators.IS_NOT_IN_DB(db, field)
  72         if not field.notnull:
  73             requires = validators.IS_EMPTY_OR(requires)
  74         return requires
  75     # does not get here for reference and list:reference
  76     if field.unique:
  77         requires.insert(0,validators.IS_NOT_IN_DB(db, field))
  78     excluded_fields = ['string','upload','text','password','boolean']
  79     if (field.notnull or field.unique) and not field_type in excluded_fields:
  80         requires.insert(0,validators.IS_NOT_EMPTY())
  81     elif not field.notnull and not field.unique and requires:
  82         requires[0] = validators.IS_EMPTY_OR(requires[0])
  83     return requires
  84 
  85 from gluon.serializers import custom_json, xml
  86 from gluon.utils import web2py_uuid
  87 from gluon import sqlhtml
  88 
  89 
  90 DAL.serializers = {'json': custom_json, 'xml': xml}
  91 DAL.validators_method = _default_validators
  92 DAL.uuid = lambda x: web2py_uuid()
  93 DAL.representers = {
  94     'rows_render': sqlhtml.represent,
  95     'rows_xml': sqlhtml.SQLTABLE
  96     }
  97 DAL.Field = Field
  98 DAL.Table = Table
  99 
  100 #: add web2py contrib drivers to pyDAL
  101 from pydal.drivers import DRIVERS
  102 if not DRIVERS.get('pymysql'):
  103     try:
  104         from .contrib import pymysql
  105         DRIVERS['pymysql'] = pymysql
  106     except:
  107         pass
  108 if not DRIVERS.get('pyodbc'):
  109     try:
  110         from .contrib import pypyodbc as pyodbc
  111         DRIVERS['pyodbc'] = pyodbc
  112     except:
  113         pass
  114 if not DRIVERS.get('pg8000'):
  115     try:
  116         from .contrib import pg8000
  117         DRIVERS['pg8000'] = pg8000
  118     except:
  119         pass
  120
  [end of gluon/dal.py]
  </code>
  
  I need you to solve this issue by generating a single patch file that I can apply directly to this repository using git apply. Please respond with a single patch file in the following format.
  <patch>
  diff --git a/file.py b/file.py
  --- a/file.py
  +++ b/file.py
  @@ -1,27 +1,35 @@
   def euclidean(a, b):
  -    while b:
  -        a, b = b, a % b
  -    return a
  +    if b == 0:
  +        return a
  +    return euclidean(b, a % b)
   
   
   def bresenham(x0, y0, x1, y1):
       points = []
       dx = abs(x1 - x0)
       dy = abs(y1 - y0)
  -    sx = 1 if x0 < x1 else -1
  -    sy = 1 if y0 < y1 else -1
  -    err = dx - dy
  +    x, y = x0, y0
  +    sx = -1 if x0 > x1 else 1
  +    sy = -1 if y0 > y1 else 1
   
  -    while True:
  -        points.append((x0, y0))
  -        if x0 == x1 and y0 == y1:
  -            break
  -        e2 = 2 * err
  -        if e2 > -dy:
  -            err -= dy
  -            x0 += sx
  -        if e2 < dx:
  -            err += dx
  -            y0 += sy
  +    if dx > dy:
  +        err = dx / 2.0
  +        while x != x1:
  +            points.append((x, y))
  +            err -= dy
  +            if err < 0:
  +                y += sy
  +                err += dx
  +            x += sx
  +    else:
  +        err = dy / 2.0
  +        while y != y1:
  +            points.append((x, y))
  +            err -= dx
  +            if err < 0:
  +                x += sx
  +                err += dy
  +            y += sy
  +
  +    points.append((x, y))
       return points
  
  </patch>
golden_diff: diff --git a/gluon/dal.py b/gluon/dal.py
  --- a/gluon/dal.py
  +++ b/gluon/dal.py
  @@ -74,12 +74,12 @@
           return requires
       # does not get here for reference and list:reference
       if field.unique:
  -        requires.insert(0,validators.IS_NOT_IN_DB(db, field))
  -    excluded_fields = ['string','upload','text','password','boolean']
  +        requires.insert(0, validators.IS_NOT_IN_DB(db, field))
  +    excluded_fields = ['string', 'upload', 'text', 'password', 'boolean']
       if (field.notnull or field.unique) and not field_type in excluded_fields:
  -        requires.insert(0,validators.IS_NOT_EMPTY())
  +        requires.insert(0, validators.IS_NOT_EMPTY())
       elif not field.notnull and not field.unique and requires:
  -        requires[0] = validators.IS_EMPTY_OR(requires[0])
  +        requires[0] = validators.IS_EMPTY_OR(requires[0], null='' if field in ('string', 'text', 'password') else None)
       return requires
   
   from gluon.serializers import custom_json, xml
  @@ -93,7 +93,7 @@
   DAL.representers = {
       'rows_render': sqlhtml.represent,
       'rows_xml': sqlhtml.SQLTABLE
  -    }
  +}
   DAL.Field = Field
   DAL.Table = Table
  
verification_info: {"golden_diff": "diff --git a/gluon/dal.py b/gluon/dal.py\n--- a/gluon/dal.py\n+++ b/gluon/dal.py\n@@ -74,12 +74,12 @@\n         return requires\n     # does not get here for reference and list:reference\n     if field.unique:\n-        requires.insert(0,validators.IS_NOT_IN_DB(db, field))\n-    excluded_fields = ['string','upload','text','password','boolean']\n+        requires.insert(0, validators.IS_NOT_IN_DB(db, field))\n+    excluded_fields = ['string', 'upload', 'text', 'password', 'boolean']\n     if (field.notnull or field.unique) and not field_type in excluded_fields:\n-        requires.insert(0,validators.IS_NOT_EMPTY())\n+        requires.insert(0, validators.IS_NOT_EMPTY())\n     elif not field.notnull and not field.unique and requires:\n-        requires[0] = validators.IS_EMPTY_OR(requires[0])\n+        requires[0] = validators.IS_EMPTY_OR(requires[0], null='' if field in ('string', 'text', 'password') else None)\n     return requires\n \n from gluon.serializers import custom_json, xml\n@@ -93,7 +93,7 @@\n DAL.representers = {\n     'rows_render': sqlhtml.represent,\n     'rows_xml': sqlhtml.SQLTABLE\n-    }\n+}\n DAL.Field = Field\n DAL.Table = Table\n", "issue": "empty strings stored as NULL in db\nhttps://groups.google.com/forum/#!topic/web2py/IYzhhd3eKXQ\n\n", "before_files": [{"content": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"\n| This file is part of the web2py Web Framework\n| Copyrighted by Massimo Di Pierro <mdipierro@cs.depaul.edu>\n| License: LGPLv3 (http://www.gnu.org/licenses/lgpl.html)\n\nTakes care of adapting pyDAL to web2py's needs\n-----------------------------------------------\n\"\"\"\n\nfrom pydal import DAL as DAL\nfrom pydal import Field\nfrom pydal.objects import Row, Rows, Table, Query, Set, Expression\nfrom pydal import SQLCustomType, geoPoint, geoLine, geoPolygon\n\n\ndef _default_validators(db, field):\n    \"\"\"\n    Field type validation, using web2py's validators mechanism.\n\n    makes sure the content of a field is in line with the declared\n    fieldtype\n    \"\"\"\n    from gluon import validators\n    field_type, field_length = field.type, field.length\n    requires = []\n\n    if field_type in (('string', 'text', 'password')):\n        requires.append(validators.IS_LENGTH(field_length))\n    elif field_type == 'json':\n        requires.append(validators.IS_EMPTY_OR(validators.IS_JSON()))\n    elif field_type == 'double' or field_type == 'float':\n        requires.append(validators.IS_FLOAT_IN_RANGE(-1e100, 1e100))\n    elif field_type == 'integer':\n        requires.append(validators.IS_INT_IN_RANGE(-2**31, 2**31))\n    elif field_type == 'bigint':\n        requires.append(validators.IS_INT_IN_RANGE(-2**63, 2**63))\n    elif field_type.startswith('decimal'):\n        requires.append(validators.IS_DECIMAL_IN_RANGE(-10**10, 10**10))\n    elif field_type == 'date':\n        requires.append(validators.IS_DATE())\n    elif field_type == 'time':\n        requires.append(validators.IS_TIME())\n    elif field_type == 'datetime':\n        requires.append(validators.IS_DATETIME())\n    elif db and field_type.startswith('reference') and \\\n            field_type.find('.') < 0 and \\\n            field_type[10:] in db.tables:\n        referenced = db[field_type[10:]]\n        if hasattr(referenced, '_format') and referenced._format:\n            requires = validators.IS_IN_DB(db, referenced._id,\n                                           referenced._format)\n            if field.unique:\n                requires._and = validators.IS_NOT_IN_DB(db, field)\n            if field.tablename == field_type[10:]:\n                return validators.IS_EMPTY_OR(requires)\n            return requires\n    elif db and field_type.startswith('list:reference') and \\\n            field_type.find('.') < 0 and \\\n            field_type[15:] in db.tables:\n        referenced = db[field_type[15:]]\n        if hasattr(referenced, '_format') and referenced._format:\n            requires = validators.IS_IN_DB(db, referenced._id,\n                                           referenced._format, multiple=True)\n        else:\n            requires = validators.IS_IN_DB(db, referenced._id,\n                                           multiple=True)\n        if field.unique:\n            requires._and = validators.IS_NOT_IN_DB(db, field)\n        if not field.notnull:\n            requires = validators.IS_EMPTY_OR(requires)\n        return requires\n    # does not get here for reference and list:reference\n    if field.unique:\n        requires.insert(0,validators.IS_NOT_IN_DB(db, field))\n    excluded_fields = ['string','upload','text','password','boolean']\n    if (field.notnull or field.unique) and not field_type in excluded_fields:\n        requires.insert(0,validators.IS_NOT_EMPTY())\n    elif not field.notnull and not field.unique and requires:\n        requires[0] = validators.IS_EMPTY_OR(requires[0])\n    return requires\n\nfrom gluon.serializers import custom_json, xml\nfrom gluon.utils import web2py_uuid\nfrom gluon import sqlhtml\n\n\nDAL.serializers = {'json': custom_json, 'xml': xml}\nDAL.validators_method = _default_validators\nDAL.uuid = lambda x: web2py_uuid()\nDAL.representers = {\n    'rows_render': sqlhtml.represent,\n    'rows_xml': sqlhtml.SQLTABLE\n    }\nDAL.Field = Field\nDAL.Table = Table\n\n#: add web2py contrib drivers to pyDAL\nfrom pydal.drivers import DRIVERS\nif not DRIVERS.get('pymysql'):\n    try:\n        from .contrib import pymysql\n        DRIVERS['pymysql'] = pymysql\n    except:\n        pass\nif not DRIVERS.get('pyodbc'):\n    try:\n        from .contrib import pypyodbc as pyodbc\n        DRIVERS['pyodbc'] = pyodbc\n    except:\n        pass\nif not DRIVERS.get('pg8000'):\n    try:\n        from .contrib import pg8000\n        DRIVERS['pg8000'] = pg8000\n    except:\n        pass\n", "path": "gluon/dal.py"}]}