Repository: googleapis/python-spanner-django

Issue:
dbapi: add support for param_types
Trying to run the Django test suite currently gives:
```
Creating test database for alias 'default'...
Traceback (most recent call last):
  File "/home/tim/code/spanner-orm/spanner/dbapi/cursor.py", line 82, in execute
    self.__session.run_in_transaction(self.__do_execute_update, sql, args or None)
  File "/home/tim/.virtualenvs/django37/lib/python3.7/site-packages/google/cloud/spanner_v1/session.py", line 299, in run_in_transaction
    return_value = func(txn, *args, **kw)
  File "/home/tim/code/spanner-orm/spanner/dbapi/cursor.py", line 97, in __do_execute_update
    res = transaction.execute_update(sql, *args, **kwargs)
  File "/home/tim/.virtualenvs/django37/lib/python3.7/site-packages/google/cloud/spanner_v1/transaction.py", line 188, in execute_update
    params_pb = self._make_params_pb(params, param_types)
  File "/home/tim/.virtualenvs/django37/lib/python3.7/site-packages/google/cloud/spanner_v1/transaction.py", line 155, in _make_params_pb
    raise ValueError("Specify 'param_types' when passing 'params'.")
ValueError: Specify 'param_types' when passing 'params'.
```


Discussion:
Could you please help me with the SQL that you are trying to run? I guess I can get it from your branch
You can run any query with parameters, I imagine.
Got it thanks, this can reproduce it

```python
def run(conn):
    with conn.cursor() as cur:
        cur.execute('SELECT * from AckWorthSingers WHERE SingerId!=?', 10)
        cur.execute(stmt)
        rows = cur.fetchmany(100)
        for i, row in enumerate(rows):
            print(i, row)
```

Resolving patch:
diff --git a/spanner/dbapi/cursor.py b/spanner/dbapi/cursor.py
--- a/spanner/dbapi/cursor.py
+++ b/spanner/dbapi/cursor.py
@@ -76,10 +76,29 @@ def execute(self, sql, args=None):
                 self.__do_update_ddl(sql)
 
             elif classify_stmt(sql) == STMT_NON_UPDATING:
-                self.__do_execute_non_update(sql, args or None)
+                self.__do_execute_non_update(
+                    sql, args or None,
+                    # param_types aren't actually required but an empty dict must be passed
+                    # to avoid
+                    #   "ValueError("Specify 'param_types' when passing 'params'.").
+                    # See https://github.com/orijtech/spanner-orm/issues/35
+                    # Instead of examining every parameter and making
+                    # a corresponding protobuf cast, we can just pass
+                    # in param_types={}
+                    param_types={})
 
             else:
-                self.__session.run_in_transaction(self.__do_execute_update, sql, args or None)
+                self.__session.run_in_transaction(
+                    self.__do_execute_update,
+                    sql, args or None,
+                    # param_types aren't actually required but an empty dict must be
+                    # passed to avoid
+                    #   "ValueError("Specify 'param_types' when passing 'params'.").
+                    # See https://github.com/orijtech/spanner-orm/issues/35
+                    # Instead of examining every parameter and making
+                    # a corresponding protobuf cast, we can just pass
+                    # in param_types={}
+                    param_types={})
 
         except grpc_exceptions.AlreadyExists as e:
             raise IntegrityError(e.details if hasattr(e, 'details') else e)


Test patch: