diff --git a/src/SqlAsyncCollector.cs b/src/SqlAsyncCollector.cs
index f90c45e08..fb4f7161b 100644
--- a/src/SqlAsyncCollector.cs
+++ b/src/SqlAsyncCollector.cs
@@ -57,6 +57,7 @@ public enum QueryType
/// A user-defined POCO that represents a row of the user's table
internal class SqlAsyncCollector : IAsyncCollector, IDisposable
{
+ private static readonly string[] UnsupportedTypes = { "NTEXT(*)", "TEXT(*)", "IMAGE(*)" };
private const string RowDataParameter = "@rowData";
private const string ColumnName = "COLUMN_NAME";
private const string ColumnDefinition = "COLUMN_DEFINITION";
@@ -231,7 +232,15 @@ private async Task UpsertRowsAsync(IList rows, SqlAttribute attribute, IConfi
throw ex;
}
- IEnumerable bracketedColumnNamesFromItem = GetColumnNamesFromItem(rows.First())
+ IEnumerable columnNamesFromItem = GetColumnNamesFromItem(rows.First());
+ IEnumerable unsupportedColumns = columnNamesFromItem.Where(prop => UnsupportedTypes.Contains(tableInfo.Columns[prop], StringComparer.OrdinalIgnoreCase));
+ if (unsupportedColumns.Any())
+ {
+ string message = $"The type(s) of the following column(s) are not supported: {string.Join(", ", unsupportedColumns.ToArray())}. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details.";
+ throw new InvalidOperationException(message);
+ }
+
+ IEnumerable bracketedColumnNamesFromItem = columnNamesFromItem
.Where(prop => !tableInfo.PrimaryKeys.Any(k => k.IsIdentity && string.Equals(k.Name, prop, StringComparison.Ordinal))) // Skip any identity columns, those should never be updated
.Select(prop => prop.AsBracketQuotedString());
if (!bracketedColumnNamesFromItem.Any())
diff --git a/test-outofproc/AddProductUnsupportedTypes.cs b/test-outofproc/AddProductUnsupportedTypes.cs
new file mode 100644
index 000000000..b6204f79f
--- /dev/null
+++ b/test-outofproc/AddProductUnsupportedTypes.cs
@@ -0,0 +1,32 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Extensions.Sql;
+using DotnetIsolatedTests.Common;
+using Microsoft.AspNetCore.Http;
+
+namespace DotnetIsolatedTests
+{
+ public static class AddProductUnsupportedTypes
+ {
+ ///
+ /// This output binding should fail since the target table has unsupported column types.
+ ///
+ [Function("AddProductUnsupportedTypes")]
+ [SqlOutput("dbo.ProductsUnsupportedTypes", "SqlConnectionString")]
+ public static ProductUnsupportedTypes Run(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")]
+ HttpRequest req)
+ {
+ var product = new ProductUnsupportedTypes
+ {
+ ProductId = 1,
+ TextCol = "test",
+ NtextCol = "test",
+ ImageCol = new byte[] { 1, 2, 3 }
+ };
+ return product;
+ }
+ }
+}
diff --git a/test-outofproc/GlobalSuppressions.cs b/test-outofproc/GlobalSuppressions.cs
index c83dffa97..98e12cbf1 100644
--- a/test-outofproc/GlobalSuppressions.cs
+++ b/test-outofproc/GlobalSuppressions.cs
@@ -14,4 +14,5 @@
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductMissingColumnsExceptionFunction.Run(Microsoft.AspNetCore.Http.HttpRequest)~DotnetIsolatedTests.Common.ProductMissingColumns")]
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductsNoPartialUpsert.Run(Microsoft.AspNetCore.Http.HttpRequest)~System.Collections.Generic.List{DotnetIsolatedTests.Common.Product}")]
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.GetProductsColumnTypesSerialization.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{DotnetIsolatedTests.Common.ProductColumnTypes})~System.Collections.Generic.IEnumerable{DotnetIsolatedTests.Common.ProductColumnTypes}")]
-[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductIncorrectCasing.Run(Microsoft.Azure.Functions.Worker.Http.HttpRequestData)~DotnetIsolatedTests.Common.ProductIncorrectCasing")]
\ No newline at end of file
+[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductIncorrectCasing.Run(Microsoft.Azure.Functions.Worker.Http.HttpRequestData)~DotnetIsolatedTests.Common.ProductIncorrectCasing")]
+[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:DotnetIsolatedTests.AddProductUnsupportedTypes.Run(Microsoft.AspNetCore.Http.HttpRequest)~DotnetIsolatedTests.Common.ProductUnsupportedTypes")]
\ No newline at end of file
diff --git a/test-outofproc/Product.cs b/test-outofproc/Product.cs
index d797ff20e..789950ab3 100644
--- a/test-outofproc/Product.cs
+++ b/test-outofproc/Product.cs
@@ -188,4 +188,15 @@ public class ProductMissingColumns
public string Name { get; set; }
}
+
+ public class ProductUnsupportedTypes
+ {
+ public int ProductId { get; set; }
+
+ public string TextCol { get; set; }
+
+ public string NtextCol { get; set; }
+
+ public byte[] ImageCol { get; set; }
+ }
}
\ No newline at end of file
diff --git a/test/Common/ProductUnsupportedTypes.cs b/test/Common/ProductUnsupportedTypes.cs
new file mode 100644
index 000000000..c5fb39a5d
--- /dev/null
+++ b/test/Common/ProductUnsupportedTypes.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common
+{
+ public class ProductUnsupportedTypes
+ {
+ public int ProductId { get; set; }
+
+ public string TextCol { get; set; }
+
+ public string NtextCol { get; set; }
+
+ public byte[] ImageCol { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/test/Database/Tables/ProductsUnsupportedTypes.sql b/test/Database/Tables/ProductsUnsupportedTypes.sql
new file mode 100644
index 000000000..8ce9b011c
--- /dev/null
+++ b/test/Database/Tables/ProductsUnsupportedTypes.sql
@@ -0,0 +1,6 @@
+CREATE TABLE [ProductsUnsupportedTypes] (
+ [ProductId] [int] NOT NULL PRIMARY KEY,
+ [TextCol] [text],
+ [NtextCol] [ntext],
+ [ImageCol] [image]
+)
\ No newline at end of file
diff --git a/test/GlobalSuppressions.cs b/test/GlobalSuppressions.cs
index 72e1de225..0664243d7 100644
--- a/test/GlobalSuppressions.cs
+++ b/test/GlobalSuppressions.cs
@@ -19,4 +19,5 @@
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.UnsupportedColumnTypesTrigger.Run(System.Collections.Generic.IReadOnlyList{Microsoft.Azure.WebJobs.Extensions.Sql.SqlChange{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})")]
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductsColumnTypesSerializationAsyncEnumerable.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IAsyncEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductColumnTypes},Microsoft.Extensions.Logging.ILogger)~System.Threading.Tasks.Task{Microsoft.AspNetCore.Mvc.IActionResult}")]
[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductsColumnTypesSerialization.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductColumnTypes},Microsoft.Extensions.Logging.ILogger)~Microsoft.AspNetCore.Mvc.IActionResult")]
-[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductIncorrectCasing.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductIncorrectCasing@)~Microsoft.AspNetCore.Mvc.IActionResult")]
\ No newline at end of file
+[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductIncorrectCasing.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductIncorrectCasing@)~Microsoft.AspNetCore.Mvc.IActionResult")]
+[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration.AddProductUnsupportedTypes.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common.ProductUnsupportedTypes@)~Microsoft.AspNetCore.Mvc.IActionResult")]
\ No newline at end of file
diff --git a/test/Integration/SqlOutputBindingIntegrationTests.cs b/test/Integration/SqlOutputBindingIntegrationTests.cs
index 87061700d..fd4e27c9a 100644
--- a/test/Integration/SqlOutputBindingIntegrationTests.cs
+++ b/test/Integration/SqlOutputBindingIntegrationTests.cs
@@ -501,5 +501,26 @@ public async Task NoPropertiesThrows(SupportedLanguages lang)
// Wait 2sec for message to get processed to account for delays reading output
await foundExpectedMessageSource.Task.TimeoutAfter(TimeSpan.FromMilliseconds(2000), $"Timed out waiting for expected error message");
}
+
+ ///
+ /// Tests that an error is thrown when the upserted item contains a unsupported column type.
+ ///
+ [Theory]
+ [SqlInlineData()]
+ [UnsupportedLanguages(SupportedLanguages.OutOfProc)]
+ public async Task AddProductUnsupportedTypesTest(SupportedLanguages lang)
+ {
+ var foundExpectedMessageSource = new TaskCompletionSource();
+ this.StartFunctionHost(nameof(AddProductUnsupportedTypes), lang, true, (object sender, DataReceivedEventArgs e) =>
+ {
+ if (e.Data.Contains("The type(s) of the following column(s) are not supported: TextCol, NtextCol, ImageCol. See https://github.com/Azure/azure-functions-sql-extension#output-bindings for more details."))
+ {
+ foundExpectedMessageSource.SetResult(true);
+ }
+ });
+
+ Assert.Throws(() => this.SendOutputGetRequest("addproduct-unsupportedtypes").Wait());
+ await foundExpectedMessageSource.Task.TimeoutAfter(TimeSpan.FromMilliseconds(2000), $"Timed out waiting for expected error message");
+ }
}
}
diff --git a/test/Integration/test-csharp/AddProductUnsupportedTypes.cs b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs
new file mode 100644
index 000000000..6f4b4ccbe
--- /dev/null
+++ b/test/Integration/test-csharp/AddProductUnsupportedTypes.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Azure.WebJobs.Extensions.Http;
+using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common;
+namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration
+{
+ public static class AddProductUnsupportedTypes
+ {
+ // This output binding should throw an exception because the target table has unsupported column types.
+ [FunctionName("AddProductUnsupportedTypes")]
+ public static IActionResult Run(
+ [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "addproduct-unsupportedtypes")]
+ HttpRequest req,
+ [Sql("dbo.ProductsUnsupportedTypes", "SqlConnectionString")] out ProductUnsupportedTypes product)
+ {
+ product = new ProductUnsupportedTypes()
+ {
+ ProductId = 1,
+ TextCol = "test",
+ NtextCol = "test",
+ ImageCol = new byte[] { 1, 2, 3 }
+ };
+ return new CreatedResult($"/api/addproduct-unsupportedtypes", product);
+ }
+ }
+}
diff --git a/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java
new file mode 100644
index 000000000..3be3e389d
--- /dev/null
+++ b/test/Integration/test-java/src/main/java/com/function/AddProductUnsupportedTypes.java
@@ -0,0 +1,48 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.function;
+
+import com.microsoft.azure.functions.HttpMethod;
+import com.microsoft.azure.functions.HttpRequestMessage;
+import com.microsoft.azure.functions.HttpResponseMessage;
+import com.microsoft.azure.functions.HttpStatus;
+import com.microsoft.azure.functions.OutputBinding;
+import com.microsoft.azure.functions.annotation.AuthorizationLevel;
+import com.microsoft.azure.functions.annotation.FunctionName;
+import com.microsoft.azure.functions.annotation.HttpTrigger;
+import com.microsoft.azure.functions.sql.annotation.SQLOutput;
+import com.function.Common.ProductUnsupportedTypes;
+
+import java.util.Optional;
+
+
+public class AddProductUnsupportedTypes {
+ // This output binding should throw an exception because the target table has unsupported column types.
+ @FunctionName("AddProductUnsupportedTypes")
+ public HttpResponseMessage run(
+ @HttpTrigger(
+ name = "req",
+ methods = {HttpMethod.GET},
+ authLevel = AuthorizationLevel.ANONYMOUS,
+ route = "addproduct-unsupportedtypes")
+ HttpRequestMessage> request,
+ @SQLOutput(
+ name = "product",
+ commandText = "dbo.ProductsUnsupportedTypes",
+ connectionStringSetting = "SqlConnectionString")
+ OutputBinding product) {
+
+ ProductUnsupportedTypes p = new ProductUnsupportedTypes(
+ 0,
+ "test",
+ "test",
+ "dGVzdA=="
+ );
+ product.setValue(p);
+ return request.createResponseBuilder(HttpStatus.OK).header("Content-Type", "application/json").body(product).build();
+ }
+}
diff --git a/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java
new file mode 100644
index 000000000..163c82336
--- /dev/null
+++ b/test/Integration/test-java/src/main/java/com/function/Common/ProductUnsupportedTypes.java
@@ -0,0 +1,62 @@
+/**
+ * Copyright (c) Microsoft Corporation. All rights reserved.
+ * Licensed under the MIT License. See License.txt in the project root for
+ * license information.
+ */
+
+package com.function.Common;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class ProductUnsupportedTypes {
+ @JsonProperty("ProductId")
+ private int ProductId;
+ @JsonProperty("TextCol")
+ private String TextCol;
+ @JsonProperty("NtextCol")
+ private String NtextCol;
+ @JsonProperty("ImageCol")
+ private String ImageCol;
+
+ public ProductUnsupportedTypes() {
+ }
+
+ public ProductUnsupportedTypes(int productId, String textCol, String ntextCol, String imageCol) {
+ ProductId = productId;
+ TextCol = textCol;
+ NtextCol = ntextCol;
+ ImageCol = imageCol;
+ }
+
+ public int getProductId() {
+ return ProductId;
+ }
+
+ public void setProductId(int productId) {
+ ProductId = productId;
+ }
+
+ public String getTextCol() {
+ return TextCol;
+ }
+
+ public void setTextCol(String textCol) {
+ TextCol = textCol;
+ }
+
+ public String getNtextCol() {
+ return NtextCol;
+ }
+
+ public void setNtextCol(String ntextCol) {
+ NtextCol = ntextCol;
+ }
+
+ public String getImageCol() {
+ return ImageCol;
+ }
+
+ public void setImageCol(String imageCol) {
+ ImageCol = imageCol;
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/function.json b/test/Integration/test-js/AddProductUnsupportedTypes/function.json
new file mode 100644
index 000000000..e9f3de84a
--- /dev/null
+++ b/test/Integration/test-js/AddProductUnsupportedTypes/function.json
@@ -0,0 +1,27 @@
+{
+ "bindings": [
+ {
+ "authLevel": "function",
+ "name": "req",
+ "direction": "in",
+ "type": "httpTrigger",
+ "methods": [
+ "get"
+ ],
+ "route": "addproduct-unsupportedtypes"
+ },
+ {
+ "name": "$return",
+ "type": "http",
+ "direction": "out"
+ },
+ {
+ "name": "product",
+ "type": "sql",
+ "direction": "out",
+ "commandText": "[dbo].[ProductsUnsupportedTypes]",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+}
\ No newline at end of file
diff --git a/test/Integration/test-js/AddProductUnsupportedTypes/index.js b/test/Integration/test-js/AddProductUnsupportedTypes/index.js
new file mode 100644
index 000000000..27fd65388
--- /dev/null
+++ b/test/Integration/test-js/AddProductUnsupportedTypes/index.js
@@ -0,0 +1,17 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+// This output binding should throw an exception because the target table has unsupported column types.
+module.exports = async function (context, req) {
+ context.bindings.product = {
+ ProductId: 0,
+ TextCol: "test",
+ NtextCol: "test",
+ ImageCol: "dGVzdA=="
+ }
+
+ return {
+ status: 201,
+ body: req.body
+ };
+}
\ No newline at end of file
diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json
new file mode 100644
index 000000000..741b973ad
--- /dev/null
+++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/function.json
@@ -0,0 +1,27 @@
+{
+ "bindings": [
+ {
+ "authLevel": "function",
+ "name": "Request",
+ "direction": "in",
+ "type": "httpTrigger",
+ "methods": [
+ "get"
+ ],
+ "route": "addproduct-unsupportedtypes"
+ },
+ {
+ "name": "response",
+ "type": "http",
+ "direction": "out"
+ },
+ {
+ "name": "product",
+ "type": "sql",
+ "direction": "out",
+ "commandText": "[dbo].[ProductsUnsupportedTypes]",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+}
\ No newline at end of file
diff --git a/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1 b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1
new file mode 100644
index 000000000..9794efb58
--- /dev/null
+++ b/test/Integration/test-powershell/AddProductUnsupportedTypes/run.ps1
@@ -0,0 +1,21 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License. See License.txt in the project root for license information.
+
+using namespace System.Net
+
+# This output binding should throw an exception because the target table has unsupported column types.
+param($Request)
+
+$req_body = [ordered]@{
+ ProductId=0;
+ TextCol="test";
+ NtextCol="test";
+ ImageCol="dGVzdA==";
+}
+
+Push-OutputBinding -Name product -Value $req_body
+
+Push-OutputBinding -Name response -Value ([HttpResponseContext]@{
+ StatusCode = [HttpStatusCode]::OK
+ Body = $req_body
+})
\ No newline at end of file
diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py
new file mode 100644
index 000000000..3f3a382eb
--- /dev/null
+++ b/test/Integration/test-python/AddProductUnsupportedTypes/__init__.py
@@ -0,0 +1,24 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import json
+import azure.functions as func
+from Common.productunsupportedtypes import ProductUnsupportedTypes
+
+def main(req: func.HttpRequest, product: func.Out[func.SqlRow]) -> func.HttpResponse:
+ """This output binding should throw an exception because the target table has unsupported column types.
+ """
+
+ row = func.SqlRow(ProductUnsupportedTypes(
+ 0,
+ "test",
+ "test",
+ "dGVzdA=="
+ ))
+ product.set(row)
+
+ return func.HttpResponse(
+ body=req.get_body(),
+ status_code=201,
+ mimetype="application/json"
+ )
diff --git a/test/Integration/test-python/AddProductUnsupportedTypes/function.json b/test/Integration/test-python/AddProductUnsupportedTypes/function.json
new file mode 100644
index 000000000..1a3280294
--- /dev/null
+++ b/test/Integration/test-python/AddProductUnsupportedTypes/function.json
@@ -0,0 +1,28 @@
+{
+ "scriptFile": "__init__.py",
+ "bindings": [
+ {
+ "authLevel": "function",
+ "name": "req",
+ "direction": "in",
+ "type": "httpTrigger",
+ "methods": [
+ "get"
+ ],
+ "route": "addproduct-unsupportedtypes"
+ },
+ {
+ "name": "$return",
+ "type": "http",
+ "direction": "out"
+ },
+ {
+ "name": "product",
+ "type": "sql",
+ "direction": "out",
+ "commandText": "[dbo].[ProductsUnsupportedTypes]",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+}
diff --git a/test/Integration/test-python/Common/productunsupportedtypes.py b/test/Integration/test-python/Common/productunsupportedtypes.py
new file mode 100644
index 000000000..5002c68c8
--- /dev/null
+++ b/test/Integration/test-python/Common/productunsupportedtypes.py
@@ -0,0 +1,12 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import collections
+
+class ProductUnsupportedTypes(collections.UserDict):
+ def __init__(self, productId, textCol, ntextCol, imageCol):
+ super().__init__()
+ self['ProductId'] = productId
+ self['TextCol'] = textCol
+ self['NtextCol'] = ntextCol
+ self['ImageCol'] = imageCol
\ No newline at end of file