If we call transaction.execute_sql with missing parameters in param_types, we may not get an error until iterating over the over the ResultSet (even if it's empty). This errors is: InvalidArgument('Unable to infer type for parameter ....').
spanner_dbapi.parse_utils.get_param_types
infers spanner data types from the python types. This is called downstream of django's CursorWrapper.execute. Among other problems, this means that we can't infer the spanner type for None-valued fields, and so they aren't included in param_types.
This problem shows up following the django tutorial at manage.py createsuperuser, which results in these arguments to transaction.execute_sql:
sql="INSERT INTO auth_user (id, password, last_login, is_superuser, username, first_name, last_name, email, is_staff, is_active, date_joined) VALUES (@a0, @a1, @a2, @a3, @a4, @a5, @a6, @a7, @a8, @a9, @a10)"
params={'a0': 1451803748860449997,
'a1': (hashed pwd),
'a2': None,
'a3': True,
'a4': (username),
'a5': '',
'a6': '',
'a7': '',
'a8': True,
'a9': True,
'a10': '2020-12-14T23:57:50.577202Z'}
param_types={'a0': code: INT64,
'a1': code: STRING,
'a3': code: BOOL,
'a4': code: STRING,
'a5': code: STRING,
'a6': code: STRING,
'a7': code: STRING,
'a8': code: BOOL,
'a9': code: BOOL,
'a10': code: TIMESTAMP}
Note that a2 is missing from param_types. The field last_login should be a google.cloud.spanner_v1.param_types.TIMESTAMP, but we can't infer it before the call.
Interestingly we only see the InvalidArgument error when using the emulator. The real non-emulated spanner service handles this insert without error.
This problem is at least as old as 47154d1, and existed in the spanner_dbapi package in this repo before it was moved into python-spanner.
It's not clear whether the right fix for this problem is here, in python-spanner, or in the emulator. But it does prevent us from using the emulator with apps that have models with nullable fields, including the django tutorial app.
If we call
transaction.execute_sqlwith missing parameters inparam_types, we may not get an error until iterating over the over theResultSet(even if it's empty). This errors is:InvalidArgument('Unable to infer type for parameter ....').spanner_dbapi.parse_utils.get_param_typesinfers spanner data types from the python types. This is called downstream of django's
CursorWrapper.execute. Among other problems, this means that we can't infer the spanner type forNone-valued fields, and so they aren't included inparam_types.This problem shows up following the django tutorial at
manage.py createsuperuser, which results in these arguments totransaction.execute_sql:Note that
a2is missing fromparam_types. The fieldlast_loginshould be agoogle.cloud.spanner_v1.param_types.TIMESTAMP, but we can't infer it before the call.Interestingly we only see the
InvalidArgumenterror when using the emulator. The real non-emulated spanner service handles this insert without error.This problem is at least as old as 47154d1, and existed in the
spanner_dbapipackage in this repo before it was moved into python-spanner.It's not clear whether the right fix for this problem is here, in python-spanner, or in the emulator. But it does prevent us from using the emulator with apps that have models with nullable fields, including the django tutorial app.