Skip to content
This repository was archived by the owner on Mar 6, 2026. It is now read-only.
This repository was archived by the owner on Mar 6, 2026. It is now read-only.

Percents de-escaping isn't handled when no parameters are used in the dbapi. #608

Closed

Description

@jimfulton
>>> import google.cloud.bigquery.dbapi
>>> conn = google.cloud.bigquery.dbapi.connect()
/home/jim/p/g/python-bigquery/google/cloud/bigquery/client.py:444: UserWarning: Cannot create BigQuery Storage client, the dependency google-cloud-bigquery-storage is not installed.
  warnings.warn(
>>> cursor = conn.cursor()
>>> cursor.execute("select 'foo %%', %(x)s", dict(x=1))
>>> cursor.fetchall()
[Row(('foo %', 1), {'f0_': 0, 'f1_': 1})]
>>> cursor.execute("select 'foo %%'", dict(x=1))
>>> cursor.fetchall()
[Row(('foo %',), {'f0_': 0})]
>>> cursor.execute("select 'foo %%'")
>>> cursor.fetchall()
[Row(('foo %%',), {'f0_': 0})]

Bonus:

if people don't escape:

>>> cursor.execute("select 'foo %'")
>>> cursor.fetchall()
[Row(('foo %',), {'f0_': 0})]
>>> cursor.execute("select 'foo %'", dict(x=1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/jim/p/g/python-bigquery/google/cloud/bigquery/dbapi/_helpers.py", line 273, in with_closed_check
    return method(self, *args, **kwargs)
  File "/home/jim/p/g/python-bigquery/google/cloud/bigquery/dbapi/cursor.py", line 172, in execute
    formatted_operation = _format_operation(operation, parameters=parameters)
  File "/home/jim/p/g/python-bigquery/google/cloud/bigquery/dbapi/cursor.py", line 460, in _format_operation
    return _format_operation_dict(operation, parameters)
  File "/home/jim/p/g/python-bigquery/google/cloud/bigquery/dbapi/cursor.py", line 434, in _format_operation_dict
    return operation % formatted_params
ValueError: unsupported format character ''' (0x27) at index 13

Activity

  1. added
    priority: p2Moderately-important priority. Fix may not be included in next release.
    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.
    and removed
    triage meI really want to be triaged.
    on Apr 16, 2021
  2. self-assigned this
    on Apr 16, 2021
  3. jimfulton commented on Apr 16, 2021

    @jimfulton
    ContributorAuthor

    FTR, I have a local fix. It's pretty simple. In cursor.py:

    @@ -441,7 +461,7 @@ def _format_operation(operation, parameters=None):
                 ``parameters`` argument.
         """
         if parameters is None or len(parameters) == 0:
    -        return operation
    +        return operation.replace("%%", "%")
     
         if isinstance(parameters, collections_abc.Mapping):
    
  4. plamut commented on Apr 16, 2021

    @plamut
    Contributor

    @jimfulton So the expected behavior is to always de-escape in absence of parameters, no matter what?

    It might be breaking for some of the existing parameter-less queries that happen to contain %%, but it will at least be clear that de-escaping is consistently always applied.

  5. jimfulton commented on Apr 16, 2021

    @jimfulton
    ContributorAuthor

    I think de-escaping has to be done consistently.

    I tripped over this while testing the SQLAlchemy integration, which assumes consistent de-escaping.

  6. plamut commented on Apr 16, 2021

    @plamut
    Contributor

    Fair enough. We do need to assure a good changelog message, though (note to self when merging the PR).

  7. added a commit that references this issue on Apr 16, 2021
    6502a60
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

api: bigqueryIssues related to the googleapis/python-bigquery API.dbapipriority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions