pyodbc: Queries with Table Value Parameters (TVP) when the Type table is not in the dbo schema
Environment
- Python: 3.7.4
- pyodbc: 4.0.26
- OS: macOS Mojave 10.14.5
- DB: Azure SQL 2016
- driver: ODBC Driver 17 for SQL Server
Issue
I’m glad to see TVPs are supported now. I was going through some testing against an Azure SQL database and it seems that the TVP type needs to be created on the dbo schema in order for this to work. If the TVP type is in a schema different than dbo, I get the error [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Column, parameter, or variable #1: Cannot find data type ListInt
Database setup
-- create type
CREATE TYPE [myschema].[ListInt] AS TABLE
(
[Id] INT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
-- create stored procedure
CREATE PROCEDURE [myschema].[PyOdbcTestTvp](@tvp [myschema].ListInt READONLY)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM @tvp
END
My python code
Following pyodbc sqlservertests.py
c01 = [1, 2, 3]
param_array = []
for i in range(3):
param_array.append([c01[i]])
try:
result_array = self.cursor.execute("EXEC [myschema].[PyOdbcTestTvp] ?", [param_array]).fetchall()
except Exception as ex:
print("Failed to execute PyOdbcTestTvp")
print("Exception: [" + type(ex).__name__ + "]", ex.args)
The example works as expected if the TVP type is created in the dbo schema like this:
-- create type
CREATE TYPE [ListInt] AS TABLE
(
[Id] INT NOT NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);
-- create stored procedure
CREATE PROCEDURE [myschema].[PyOdbcTestTvp](@tvp ListInt READONLY)
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM @tvp
END
Is there anything I can do to make this work with the TVP type in a schema other than dbo? Thanks!
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 4
- Comments: 20 (4 by maintainers)
Thanks @v-chojas . #904 does seem to do the trick.
So the fix is to use string values to explicitly specify the name of the type and its schema as the first two elements of the TVP “value”. In the example above:
TODO: Once #904 gets merged and released we should probably add an entry in the wiki.
I am also interested in this issue. My employer deals with a lot of databases with many different schemas. To work around this issue I’ve been using global temp tables, as a workaround. This bug fix would be a great benefit.
@v-chojas , @v-makouz – Any feedback from my comments of 2019-07-25 and 2019-08-06? It really does look like the ODBC driver is the one responsible for
the call
and the output from
does tell the driver that the (“suggested”) schema name is
myschema. I don’t really see how pyodbc can work around the issue because the “conversation” between pyodbc and the driver only involves the(Note that December 25 will not only be Christmas Day, but it will also be the day that this issue turns seventeen (17) months old.)
@gordthompson Ah, OK, thanks, I got a little confused by the two similar SQLs, it all makes sense now, I can repro and looking into it
Additional information:
I’m not sure to what extent pyodbc is directly involved in creating the
exec sp_preparecall, but the output fromdoes include ‘myschema’ as the “suggested_user_type_schema”:
I am able to reproduce the issue. pyodbc seems to be going through the usual motions, successfully calling
SQLPrepareW,SQLDescribeParam,SQLBindParameter, and so on, but when it finally gets toSQLExecuteit fails withSQL Profiler shows that we’re calling …
… followed by …
… and that’s failing, probably because the
[ListInt]reference is not qualified so it must be looking in the current default schema, which isdbofor my login.