prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Database migration fails if the URI contains '%' signs
  If the `SQLALCHEMY_DATABASE_URI` contains query parameters like `ssl_ca=/path/to/cert` the path separators will be url-encoded with `%` signs.
  This fails when passing the URI to the alembic configuration (https://alembic.sqlalchemy.org/en/latest/api/config.html#alembic.config.Config.set_main_option).
  The `%` signs should be escaped in the URI string before passing it to alembic.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `migrations/env.py`
  Content:
  ```
  1 from __future__ import with_statement
  2 from alembic import context
  3 from sqlalchemy import engine_from_config, pool
  4 from sqlalchemy.engine.url import make_url
  5 from logging.config import fileConfig
  6 
  7 # this is the Alembic Config object, which provides
  8 # access to the values within the .ini file in use.
  9 
  10 config = context.config
  11 
  12 # Interpret the config file for Python logging.
  13 # This line sets up loggers basically.
  14 fileConfig(config.config_file_name)
  15 
  16 # add your model's MetaData object here
  17 # for 'autogenerate' support
  18 # from myapp import mymodel
  19 # target_metadata = mymodel.Base.metadata
  20 from flask import current_app
  21 
  22 
  23 def set_database_url(config):
  24     url = current_app.config.get('SQLALCHEMY_DATABASE_URI')
  25     try:
  26         # In case of MySQL, add ``charset=utf8`` to the parameters (if no charset is set),
  27         # because this is what Flask-SQLAlchemy does
  28         if url.startswith("mysql"):
  29             parsed_url = make_url(url)
  30             parsed_url.query.setdefault("charset", "utf8")
  31             url = str(parsed_url)
  32     except Exception as exx:
  33         print(u"Attempted to set charset=utf8 on connection, but failed: {}".format(exx))
  34     config.set_main_option('sqlalchemy.url', url)
  35 
  36 
  37 set_database_url(config)
  38 target_metadata = current_app.extensions['migrate'].db.metadata
  39 
  40 # other values from the config, defined by the needs of env.py,
  41 # can be acquired:
  42 # my_important_option = config.get_main_option("my_important_option")
  43 # ... etc.
  44 
  45 
  46 def run_migrations_offline():
  47     """Run migrations in 'offline' mode.
  48 
  49     This configures the context with just a URL
  50     and not an Engine, though an Engine is acceptable
  51     here as well.  By skipping the Engine creation
  52     we don't even need a DBAPI to be available.
  53 
  54     Calls to context.execute() here emit the given string to the
  55     script output.
  56 
  57     """
  58     url = config.get_main_option("sqlalchemy.url")
  59     context.configure(url=url)
  60 
  61     with context.begin_transaction():
  62         context.run_migrations()
  63 
  64 
  65 def run_migrations_online():
  66     """Run migrations in 'online' mode.
  67 
  68     In this scenario we need to create an Engine
  69     and associate a connection with the context.
  70 
  71     """
  72     # FIX for Postgres updates
  73     url = config.get_section(config.config_ini_section).get("sqlalchemy.url")
  74     driver = url.split(":")[0]
  75 
  76     if driver == "postgresql+psycopg2":
  77         engine = engine_from_config(
  78                     config.get_section(config.config_ini_section),
  79                     prefix='sqlalchemy.',
  80                     isolation_level="AUTOCOMMIT",
  81                     poolclass=pool.NullPool)
  82     else:
  83         engine = engine_from_config(
  84                     config.get_section(config.config_ini_section),
  85                     prefix='sqlalchemy.',
  86                     poolclass=pool.NullPool)
  87 
  88     connection = engine.connect()
  89     context.configure(
  90                 connection=connection,
  91                 target_metadata=target_metadata,
  92                 compare_type=True
  93                 )
  94 
  95     try:
  96         with context.begin_transaction():
  97             context.run_migrations()
  98     finally:
  99         connection.close()
  100 
  101 if context.is_offline_mode():
  102     print("Running offline")
  103     run_migrations_offline()
  104 else:
  105     print("Running online")
  106     run_migrations_online()
  107 
  108
  ```
  --- 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/migrations/env.py b/migrations/env.py
  --- a/migrations/env.py
  +++ b/migrations/env.py
  @@ -3,6 +3,7 @@
   from sqlalchemy import engine_from_config, pool
   from sqlalchemy.engine.url import make_url
   from logging.config import fileConfig
  +from six.moves.urllib.parse import quote
   
   # this is the Alembic Config object, which provides
   # access to the values within the .ini file in use.
  @@ -28,10 +29,13 @@
           if url.startswith("mysql"):
               parsed_url = make_url(url)
               parsed_url.query.setdefault("charset", "utf8")
  +            # We need to quote the password in case it contains special chars
  +            parsed_url.password = quote(parsed_url.password)
               url = str(parsed_url)
       except Exception as exx:
           print(u"Attempted to set charset=utf8 on connection, but failed: {}".format(exx))
  -    config.set_main_option('sqlalchemy.url', url)
  +    # set_main_option() requires escaped "%" signs in the string
  +    config.set_main_option('sqlalchemy.url', url.replace('%', '%%'))
   
   
   set_database_url(config)
  @@ -98,10 +102,10 @@
       finally:
           connection.close()
   
  +
   if context.is_offline_mode():
       print("Running offline")
       run_migrations_offline()
   else:
       print("Running online")
       run_migrations_online()
  -
  
verification_info: {"golden_diff": "diff --git a/migrations/env.py b/migrations/env.py\n--- a/migrations/env.py\n+++ b/migrations/env.py\n@@ -3,6 +3,7 @@\n from sqlalchemy import engine_from_config, pool\n from sqlalchemy.engine.url import make_url\n from logging.config import fileConfig\n+from six.moves.urllib.parse import quote\n \n # this is the Alembic Config object, which provides\n # access to the values within the .ini file in use.\n@@ -28,10 +29,13 @@\n         if url.startswith(\"mysql\"):\n             parsed_url = make_url(url)\n             parsed_url.query.setdefault(\"charset\", \"utf8\")\n+            # We need to quote the password in case it contains special chars\n+            parsed_url.password = quote(parsed_url.password)\n             url = str(parsed_url)\n     except Exception as exx:\n         print(u\"Attempted to set charset=utf8 on connection, but failed: {}\".format(exx))\n-    config.set_main_option('sqlalchemy.url', url)\n+    # set_main_option() requires escaped \"%\" signs in the string\n+    config.set_main_option('sqlalchemy.url', url.replace('%', '%%'))\n \n \n set_database_url(config)\n@@ -98,10 +102,10 @@\n     finally:\n         connection.close()\n \n+\n if context.is_offline_mode():\n     print(\"Running offline\")\n     run_migrations_offline()\n else:\n     print(\"Running online\")\n     run_migrations_online()\n-\n", "issue": "Database migration fails if the URI contains '%' signs\nIf the `SQLALCHEMY_DATABASE_URI` contains query parameters like `ssl_ca=/path/to/cert` the path separators will be url-encoded with `%` signs.\r\nThis fails when passing the URI to the alembic configuration (https://alembic.sqlalchemy.org/en/latest/api/config.html#alembic.config.Config.set_main_option).\r\nThe `%` signs should be escaped in the URI string before passing it to alembic.\n", "before_files": [{"content": "from __future__ import with_statement\nfrom alembic import context\nfrom sqlalchemy import engine_from_config, pool\nfrom sqlalchemy.engine.url import make_url\nfrom logging.config import fileConfig\n\n# this is the Alembic Config object, which provides\n# access to the values within the .ini file in use.\n\nconfig = context.config\n\n# Interpret the config file for Python logging.\n# This line sets up loggers basically.\nfileConfig(config.config_file_name)\n\n# add your model's MetaData object here\n# for 'autogenerate' support\n# from myapp import mymodel\n# target_metadata = mymodel.Base.metadata\nfrom flask import current_app\n\n\ndef set_database_url(config):\n    url = current_app.config.get('SQLALCHEMY_DATABASE_URI')\n    try:\n        # In case of MySQL, add ``charset=utf8`` to the parameters (if no charset is set),\n        # because this is what Flask-SQLAlchemy does\n        if url.startswith(\"mysql\"):\n            parsed_url = make_url(url)\n            parsed_url.query.setdefault(\"charset\", \"utf8\")\n            url = str(parsed_url)\n    except Exception as exx:\n        print(u\"Attempted to set charset=utf8 on connection, but failed: {}\".format(exx))\n    config.set_main_option('sqlalchemy.url', url)\n\n\nset_database_url(config)\ntarget_metadata = current_app.extensions['migrate'].db.metadata\n\n# other values from the config, defined by the needs of env.py,\n# can be acquired:\n# my_important_option = config.get_main_option(\"my_important_option\")\n# ... etc.\n\n\ndef run_migrations_offline():\n    \"\"\"Run migrations in 'offline' mode.\n\n    This configures the context with just a URL\n    and not an Engine, though an Engine is acceptable\n    here as well.  By skipping the Engine creation\n    we don't even need a DBAPI to be available.\n\n    Calls to context.execute() here emit the given string to the\n    script output.\n\n    \"\"\"\n    url = config.get_main_option(\"sqlalchemy.url\")\n    context.configure(url=url)\n\n    with context.begin_transaction():\n        context.run_migrations()\n\n\ndef run_migrations_online():\n    \"\"\"Run migrations in 'online' mode.\n\n    In this scenario we need to create an Engine\n    and associate a connection with the context.\n\n    \"\"\"\n    # FIX for Postgres updates\n    url = config.get_section(config.config_ini_section).get(\"sqlalchemy.url\")\n    driver = url.split(\":\")[0]\n\n    if driver == \"postgresql+psycopg2\":\n        engine = engine_from_config(\n                    config.get_section(config.config_ini_section),\n                    prefix='sqlalchemy.',\n                    isolation_level=\"AUTOCOMMIT\",\n                    poolclass=pool.NullPool)\n    else:\n        engine = engine_from_config(\n                    config.get_section(config.config_ini_section),\n                    prefix='sqlalchemy.',\n                    poolclass=pool.NullPool)\n\n    connection = engine.connect()\n    context.configure(\n                connection=connection,\n                target_metadata=target_metadata,\n                compare_type=True\n                )\n\n    try:\n        with context.begin_transaction():\n            context.run_migrations()\n    finally:\n        connection.close()\n\nif context.is_offline_mode():\n    print(\"Running offline\")\n    run_migrations_offline()\nelse:\n    print(\"Running online\")\n    run_migrations_online()\n\n", "path": "migrations/env.py"}], "after_files": [{"content": "from __future__ import with_statement\nfrom alembic import context\nfrom sqlalchemy import engine_from_config, pool\nfrom sqlalchemy.engine.url import make_url\nfrom logging.config import fileConfig\nfrom six.moves.urllib.parse import quote\n\n# this is the Alembic Config object, which provides\n# access to the values within the .ini file in use.\n\nconfig = context.config\n\n# Interpret the config file for Python logging.\n# This line sets up loggers basically.\nfileConfig(config.config_file_name)\n\n# add your model's MetaData object here\n# for 'autogenerate' support\n# from myapp import mymodel\n# target_metadata = mymodel.Base.metadata\nfrom flask import current_app\n\n\ndef set_database_url(config):\n    url = current_app.config.get('SQLALCHEMY_DATABASE_URI')\n    try:\n        # In case of MySQL, add ``charset=utf8`` to the parameters (if no charset is set),\n        # because this is what Flask-SQLAlchemy does\n        if url.startswith(\"mysql\"):\n            parsed_url = make_url(url)\n            parsed_url.query.setdefault(\"charset\", \"utf8\")\n            # We need to quote the password in case it contains special chars\n            parsed_url.password = quote(parsed_url.password)\n            url = str(parsed_url)\n    except Exception as exx:\n        print(u\"Attempted to set charset=utf8 on connection, but failed: {}\".format(exx))\n    # set_main_option() requires escaped \"%\" signs in the string\n    config.set_main_option('sqlalchemy.url', url.replace('%', '%%'))\n\n\nset_database_url(config)\ntarget_metadata = current_app.extensions['migrate'].db.metadata\n\n# other values from the config, defined by the needs of env.py,\n# can be acquired:\n# my_important_option = config.get_main_option(\"my_important_option\")\n# ... etc.\n\n\ndef run_migrations_offline():\n    \"\"\"Run migrations in 'offline' mode.\n\n    This configures the context with just a URL\n    and not an Engine, though an Engine is acceptable\n    here as well.  By skipping the Engine creation\n    we don't even need a DBAPI to be available.\n\n    Calls to context.execute() here emit the given string to the\n    script output.\n\n    \"\"\"\n    url = config.get_main_option(\"sqlalchemy.url\")\n    context.configure(url=url)\n\n    with context.begin_transaction():\n        context.run_migrations()\n\n\ndef run_migrations_online():\n    \"\"\"Run migrations in 'online' mode.\n\n    In this scenario we need to create an Engine\n    and associate a connection with the context.\n\n    \"\"\"\n    # FIX for Postgres updates\n    url = config.get_section(config.config_ini_section).get(\"sqlalchemy.url\")\n    driver = url.split(\":\")[0]\n\n    if driver == \"postgresql+psycopg2\":\n        engine = engine_from_config(\n                    config.get_section(config.config_ini_section),\n                    prefix='sqlalchemy.',\n                    isolation_level=\"AUTOCOMMIT\",\n                    poolclass=pool.NullPool)\n    else:\n        engine = engine_from_config(\n                    config.get_section(config.config_ini_section),\n                    prefix='sqlalchemy.',\n                    poolclass=pool.NullPool)\n\n    connection = engine.connect()\n    context.configure(\n                connection=connection,\n                target_metadata=target_metadata,\n                compare_type=True\n                )\n\n    try:\n        with context.begin_transaction():\n            context.run_migrations()\n    finally:\n        connection.close()\n\n\nif context.is_offline_mode():\n    print(\"Running offline\")\n    run_migrations_offline()\nelse:\n    print(\"Running online\")\n    run_migrations_online()\n", "path": "migrations/env.py"}]}