prompt: You will be provided with a partial code base and an issue statement explaining a problem to resolve.
  <issue>
  Running jupyterhub upgrade-db with PostgreSQL database fails
  **How to reproduce the issue**
  
  Run `jupyterhub upgrade-db` with a PostgreSQL database to upgrade to 99a28a4418e1.
  
  **What you expected to happen**
  
  Successful schema update.
  
  **What actually happens**
  
  It fails with an sqlalchemy `ProgrammingError` message that originates here:
  
  https://github.com/jupyterhub/jupyterhub/blob/master/jupyterhub/alembic/versions/99a28a4418e1_user_created.py#L40
  
  in particular I think that should be `IS NOT NULL` not just `NOT NULL`.  I substituted this live and it allowed the upgrade to proceed.
  
  **Share what version of JupyterHub you are using**
  
  Latest master.
  
  </issue>
  <code>
  [start of jupyterhub/alembic/versions/99a28a4418e1_user_created.py]
  1 """user.created and spawner.started
  2 
  3 Revision ID: 99a28a4418e1
  4 Revises: 56cc5a70207e
  5 Create Date: 2018-03-21 14:27:17.466841
  6 
  7 """
  8 
  9 # revision identifiers, used by Alembic.
  10 revision = '99a28a4418e1'
  11 down_revision = '56cc5a70207e'
  12 branch_labels = None
  13 depends_on = None
  14 
  15 
  16 from alembic import op
  17 import sqlalchemy as sa
  18 
  19 from datetime import datetime
  20 
  21 def upgrade():
  22     op.add_column('users', sa.Column('created', sa.DateTime, nullable=True))
  23     c = op.get_bind()
  24     # fill created date with current time
  25     now = datetime.utcnow()
  26     c.execute("""
  27         UPDATE users
  28         SET created='%s'
  29         """ % (now,)
  30     )
  31 
  32     tables = c.engine.table_names()
  33 
  34     if 'spawners' in tables:
  35         op.add_column('spawners', sa.Column('started', sa.DateTime, nullable=True))
  36         # fill started value with now for running servers
  37         c.execute("""
  38             UPDATE spawners
  39             SET started='%s'
  40             WHERE server_id NOT NULL
  41             """ % (now,)
  42         )
  43 
  44 
  45 def downgrade():
  46     op.drop_column('users', 'created')
  47     op.drop_column('spawners', 'started')
  48
  [end of jupyterhub/alembic/versions/99a28a4418e1_user_created.py]
  [start of jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py]
  1 """token tracking
  2 
  3 Revision ID: 56cc5a70207e
  4 Revises: 1cebaf56856c
  5 Create Date: 2017-12-19 15:21:09.300513
  6 
  7 """
  8 
  9 # revision identifiers, used by Alembic.
  10 revision = '56cc5a70207e'
  11 down_revision = '1cebaf56856c'
  12 branch_labels = None
  13 depends_on = None
  14 
  15 from alembic import op
  16 import sqlalchemy as sa
  17 
  18 
  19 def upgrade():
  20     tables = op.get_bind().engine.table_names()
  21     op.add_column('api_tokens', sa.Column('created', sa.DateTime(), nullable=True))
  22     op.add_column('api_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))
  23     op.add_column('api_tokens', sa.Column('note', sa.Unicode(length=1023), nullable=True))
  24     if 'oauth_access_tokens' in tables:
  25         op.add_column('oauth_access_tokens', sa.Column('created', sa.DateTime(), nullable=True))
  26         op.add_column('oauth_access_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))
  27         op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
  28         op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
  29 
  30 
  31 def downgrade():
  32     op.drop_constraint(None, 'oauth_codes', type_='foreignkey')
  33     op.drop_constraint(None, 'oauth_access_tokens', type_='foreignkey')
  34     op.drop_column('oauth_access_tokens', 'last_activity')
  35     op.drop_column('oauth_access_tokens', 'created')
  36     op.drop_column('api_tokens', 'note')
  37     op.drop_column('api_tokens', 'last_activity')
  38     op.drop_column('api_tokens', 'created')
  39
  [end of jupyterhub/alembic/versions/56cc5a70207e_token_tracking.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/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py
  --- a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py
  +++ b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py
  @@ -15,6 +15,9 @@
   from alembic import op
   import sqlalchemy as sa
   
  +import logging
  +logger = logging.getLogger('alembic')
  +
   
   def upgrade():
       tables = op.get_bind().engine.table_names()
  @@ -24,8 +27,11 @@
       if 'oauth_access_tokens' in tables:
           op.add_column('oauth_access_tokens', sa.Column('created', sa.DateTime(), nullable=True))
           op.add_column('oauth_access_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))
  -        op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
  -        op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
  +        if op.get_context().dialect.name == 'sqlite':
  +            logger.warning("sqlite cannot use ALTER TABLE to create foreign keys. Upgrade will be incomplete.")
  +        else:
  +            op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
  +            op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')
   
   
   def downgrade():
  diff --git a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py
  --- a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py
  +++ b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py
  @@ -37,7 +37,7 @@
           c.execute("""
               UPDATE spawners
               SET started='%s'
  -            WHERE server_id NOT NULL
  +            WHERE server_id IS NOT NULL
               """ % (now,)
           )
  
verification_info: {"golden_diff": "diff --git a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py\n--- a/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py\n+++ b/jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py\n@@ -15,6 +15,9 @@\n from alembic import op\n import sqlalchemy as sa\n \n+import logging\n+logger = logging.getLogger('alembic')\n+\n \n def upgrade():\n     tables = op.get_bind().engine.table_names()\n@@ -24,8 +27,11 @@\n     if 'oauth_access_tokens' in tables:\n         op.add_column('oauth_access_tokens', sa.Column('created', sa.DateTime(), nullable=True))\n         op.add_column('oauth_access_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))\n-        op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n-        op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n+        if op.get_context().dialect.name == 'sqlite':\n+            logger.warning(\"sqlite cannot use ALTER TABLE to create foreign keys. Upgrade will be incomplete.\")\n+        else:\n+            op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n+            op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n \n \n def downgrade():\ndiff --git a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py\n--- a/jupyterhub/alembic/versions/99a28a4418e1_user_created.py\n+++ b/jupyterhub/alembic/versions/99a28a4418e1_user_created.py\n@@ -37,7 +37,7 @@\n         c.execute(\"\"\"\n             UPDATE spawners\n             SET started='%s'\n-            WHERE server_id NOT NULL\n+            WHERE server_id IS NOT NULL\n             \"\"\" % (now,)\n         )\n", "issue": "Running jupyterhub upgrade-db with PostgreSQL database fails\n**How to reproduce the issue**\r\n\r\nRun `jupyterhub upgrade-db` with a PostgreSQL database to upgrade to 99a28a4418e1.\r\n\r\n**What you expected to happen**\r\n\r\nSuccessful schema update.\r\n\r\n**What actually happens**\r\n\r\nIt fails with an sqlalchemy `ProgrammingError` message that originates here:\r\n\r\nhttps://github.com/jupyterhub/jupyterhub/blob/master/jupyterhub/alembic/versions/99a28a4418e1_user_created.py#L40\r\n\r\nin particular I think that should be `IS NOT NULL` not just `NOT NULL`.  I substituted this live and it allowed the upgrade to proceed.\r\n\r\n**Share what version of JupyterHub you are using**\r\n\r\nLatest master.\n", "before_files": [{"content": "\"\"\"user.created and spawner.started\n\nRevision ID: 99a28a4418e1\nRevises: 56cc5a70207e\nCreate Date: 2018-03-21 14:27:17.466841\n\n\"\"\"\n\n# revision identifiers, used by Alembic.\nrevision = '99a28a4418e1'\ndown_revision = '56cc5a70207e'\nbranch_labels = None\ndepends_on = None\n\n\nfrom alembic import op\nimport sqlalchemy as sa\n\nfrom datetime import datetime\n\ndef upgrade():\n    op.add_column('users', sa.Column('created', sa.DateTime, nullable=True))\n    c = op.get_bind()\n    # fill created date with current time\n    now = datetime.utcnow()\n    c.execute(\"\"\"\n        UPDATE users\n        SET created='%s'\n        \"\"\" % (now,)\n    )\n\n    tables = c.engine.table_names()\n\n    if 'spawners' in tables:\n        op.add_column('spawners', sa.Column('started', sa.DateTime, nullable=True))\n        # fill started value with now for running servers\n        c.execute(\"\"\"\n            UPDATE spawners\n            SET started='%s'\n            WHERE server_id NOT NULL\n            \"\"\" % (now,)\n        )\n\n\ndef downgrade():\n    op.drop_column('users', 'created')\n    op.drop_column('spawners', 'started')\n", "path": "jupyterhub/alembic/versions/99a28a4418e1_user_created.py"}, {"content": "\"\"\"token tracking\n\nRevision ID: 56cc5a70207e\nRevises: 1cebaf56856c\nCreate Date: 2017-12-19 15:21:09.300513\n\n\"\"\"\n\n# revision identifiers, used by Alembic.\nrevision = '56cc5a70207e'\ndown_revision = '1cebaf56856c'\nbranch_labels = None\ndepends_on = None\n\nfrom alembic import op\nimport sqlalchemy as sa\n\n\ndef upgrade():\n    tables = op.get_bind().engine.table_names()\n    op.add_column('api_tokens', sa.Column('created', sa.DateTime(), nullable=True))\n    op.add_column('api_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))\n    op.add_column('api_tokens', sa.Column('note', sa.Unicode(length=1023), nullable=True))\n    if 'oauth_access_tokens' in tables:\n        op.add_column('oauth_access_tokens', sa.Column('created', sa.DateTime(), nullable=True))\n        op.add_column('oauth_access_tokens', sa.Column('last_activity', sa.DateTime(), nullable=True))\n        op.create_foreign_key(None, 'oauth_access_tokens', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n        op.create_foreign_key(None, 'oauth_codes', 'oauth_clients', ['client_id'], ['identifier'], ondelete='CASCADE')\n\n\ndef downgrade():\n    op.drop_constraint(None, 'oauth_codes', type_='foreignkey')\n    op.drop_constraint(None, 'oauth_access_tokens', type_='foreignkey')\n    op.drop_column('oauth_access_tokens', 'last_activity')\n    op.drop_column('oauth_access_tokens', 'created')\n    op.drop_column('api_tokens', 'note')\n    op.drop_column('api_tokens', 'last_activity')\n    op.drop_column('api_tokens', 'created')\n", "path": "jupyterhub/alembic/versions/56cc5a70207e_token_tracking.py"}]}