diff --git a/test-outofproc/ProductsColumnTypesTrigger.cs b/test-outofproc/ProductsColumnTypesTrigger.cs
new file mode 100644
index 000000000..e1884a328
--- /dev/null
+++ b/test-outofproc/ProductsColumnTypesTrigger.cs
@@ -0,0 +1,27 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using DotnetIsolatedTests.Common;
+using Microsoft.Extensions.Logging;
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Extensions.Sql;
+
+namespace DotnetIsolatedTests
+{
+ public static class ProductsColumnTypesTrigger
+ {
+ ///
+ /// Simple trigger function used to verify different column types are serialized correctly.
+ ///
+ [Function(nameof(ProductsColumnTypesTrigger))]
+ public static void Run(
+ [SqlTrigger("[dbo].[ProductsColumnTypes]", "SqlConnectionString")]
+ IReadOnlyList> changes,
+ FunctionContext context)
+ {
+ ILogger logger = context.GetLogger("ProductsColumnTypesTrigger");
+ logger.LogInformation("SQL Changes: " + Utils.JsonSerializeObject(changes));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/SqlTriggerBindingIntegrationTests.cs b/test/Integration/SqlTriggerBindingIntegrationTests.cs
index d41fe2010..3fbb35204 100644
--- a/test/Integration/SqlTriggerBindingIntegrationTests.cs
+++ b/test/Integration/SqlTriggerBindingIntegrationTests.cs
@@ -654,7 +654,91 @@ JOIN sys.columns c
//Check if LastAccessTime column exists in the GlobalState table
Assert.True(1 == (int)this.ExecuteScalar("SELECT 1 FROM sys.columns WHERE Name = N'LastAccessTime' AND Object_ID = Object_ID(N'[az_func].[GlobalState]')"), $"{GlobalStateTableName} should have {LastAccessTimeColumnName} column after restarting the listener.");
+ }
+
+ ///
+ /// Ensures that all column types are serialized correctly.
+ ///
+ [Theory]
+ [SqlInlineData()]
+ public async Task ProductsColumnTypesTriggerTest(SupportedLanguages lang)
+ {
+ this.SetChangeTrackingForTable("ProductsColumnTypes");
+ this.StartFunctionHost(nameof(ProductsColumnTypesTrigger), lang, true);
+ ProductColumnTypes expectedResponse = Utils.JsonDeserializeObject(/*lang=json,strict*/ "{\"ProductId\":999,\"BigInt\":999,\"Bit\":true,\"DecimalType\":1.2345,\"Money\":1.2345,\"Numeric\":1.2345,\"SmallInt\":1,\"SmallMoney\":1.2345,\"TinyInt\":1,\"FloatType\":0.1,\"Real\":0.1,\"Date\":\"2022-10-20T00:00:00.000Z\",\"Datetime\":\"2022-10-20T12:39:13.123Z\",\"Datetime2\":\"2022-10-20T12:39:13.123Z\",\"DatetimeOffset\":\"2022-10-20T12:39:13.123Z\",\"SmallDatetime\":\"2022-10-20T12:39:00.000Z\",\"Time\":\"12:39:13.1230000\",\"CharType\":\"test\",\"Varchar\":\"test\",\"Nchar\":\"test\",\"Nvarchar\":\"test\",\"Binary\":\"dGVzdA==\",\"Varbinary\":\"dGVzdA==\"}");
+ int index = 0;
+ string messagePrefix = "SQL Changes: ";
+
+ var taskCompletion = new TaskCompletionSource();
+ void MonitorOutputData(object sender, DataReceivedEventArgs e)
+ {
+ if (e.Data != null && (index = e.Data.IndexOf(messagePrefix, StringComparison.Ordinal)) >= 0)
+ {
+ string json = e.Data[(index + messagePrefix.Length)..];
+ // Sometimes we'll get messages that have extra logging content on the same line - so to prevent that from breaking
+ // the deserialization we look for the end of the changes array and only use that.
+ // (This is fine since we control what content is in the array so know that none of the items have a ] in them)
+ json = json[..(json.IndexOf(']') + 1)];
+ IReadOnlyList> changes;
+ try
+ {
+ changes = Utils.JsonDeserializeObject>>(json);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidOperationException($"Exception deserializing JSON content. Error={ex.Message} Json=\"{json}\"", ex);
+ }
+ Assert.Equal(SqlChangeOperation.Insert, changes[0].Operation); // Expected change operation
+ ProductColumnTypes product = changes[0].Item;
+ Assert.NotNull(product); // Product deserialized correctly
+ Assert.Equal(expectedResponse, product); // The product has the expected values
+ taskCompletion.SetResult(true);
+ }
+ };
+
+ // Set up listener for the changes coming in
+ foreach (Process functionHost in this.FunctionHostList)
+ {
+ functionHost.OutputDataReceived += MonitorOutputData;
+ }
+
+ // Now that we've set up our listener trigger the actions to monitor
+ string datetime = "2022-10-20 12:39:13.123";
+ this.ExecuteNonQuery("INSERT INTO [dbo].[ProductsColumnTypes] VALUES (" +
+ "999, " + // ProductId,
+ "999, " + // BigInt
+ "1, " + // Bit
+ "1.2345, " + // DecimalType
+ "1.2345, " + // Money
+ "1.2345, " + // Numeric
+ "1, " + // SmallInt
+ "1.2345, " + // SmallMoney
+ "1, " + // TinyInt
+ ".1, " + // FloatType
+ ".1, " + // Real
+ $"CONVERT(DATE, '{datetime}'), " + // Date
+ $"CONVERT(DATETIME, '{datetime}'), " + // Datetime
+ $"CONVERT(DATETIME2, '{datetime}'), " + // Datetime2
+ $"CONVERT(DATETIMEOFFSET, '{datetime}'), " + // DatetimeOffset
+ $"CONVERT(SMALLDATETIME, '{datetime}'), " + // SmallDatetime
+ $"CONVERT(TIME, '{datetime}'), " + // Time
+ "'test', " + // CharType
+ "'test', " + // Varchar
+ "'test', " + // Nchar
+ "'test', " + // Nvarchar
+ "CONVERT(BINARY, 'test'), " + // Binary
+ "CONVERT(VARBINARY, 'test'))"); // Varbinary
+
+ // Now wait until either we timeout or we've gotten all the expected changes, whichever comes first
+ this.LogOutput($"[{DateTime.UtcNow:u}] Waiting for Insert changes (10000ms)");
+ await taskCompletion.Task.TimeoutAfter(TimeSpan.FromMilliseconds(10000), $"Timed out waiting for Insert changes.");
+
+ // Unhook handler since we're done monitoring these changes so we aren't checking other changes done later
+ foreach (Process functionHost in this.FunctionHostList)
+ {
+ functionHost.OutputDataReceived -= MonitorOutputData;
+ }
}
}
}
\ No newline at end of file
diff --git a/test/Integration/test-csharp/ProductsColumnTypesTrigger.cs b/test/Integration/test-csharp/ProductsColumnTypesTrigger.cs
new file mode 100644
index 000000000..c3b6fa7e3
--- /dev/null
+++ b/test/Integration/test-csharp/ProductsColumnTypesTrigger.cs
@@ -0,0 +1,25 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+using System.Collections.Generic;
+using Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Common;
+using Microsoft.Extensions.Logging;
+
+
+namespace Microsoft.Azure.WebJobs.Extensions.Sql.Tests.Integration
+{
+ public static class ProductsColumnTypesTrigger
+ {
+ ///
+ /// Simple trigger function used to verify different column types are serialized correctly.
+ ///
+ [FunctionName(nameof(ProductsColumnTypesTrigger))]
+ public static void Run(
+ [SqlTrigger("[dbo].[ProductsColumnTypes]", "SqlConnectionString")]
+ IReadOnlyList> changes,
+ ILogger logger)
+ {
+ logger.LogInformation("SQL Changes: " + Utils.JsonSerializeObject(changes));
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/test-csx/ProductsColumnTypesTrigger/function.json b/test/Integration/test-csx/ProductsColumnTypesTrigger/function.json
new file mode 100644
index 000000000..c1aca1832
--- /dev/null
+++ b/test/Integration/test-csx/ProductsColumnTypesTrigger/function.json
@@ -0,0 +1,12 @@
+{
+ "bindings": [
+ {
+ "name": "changes",
+ "type": "sqlTrigger",
+ "direction": "in",
+ "tableName": "dbo.ProductsColumnTypes",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+}
\ No newline at end of file
diff --git a/test/Integration/test-csx/ProductsColumnTypesTrigger/run.csx b/test/Integration/test-csx/ProductsColumnTypesTrigger/run.csx
new file mode 100644
index 000000000..738cd4799
--- /dev/null
+++ b/test/Integration/test-csx/ProductsColumnTypesTrigger/run.csx
@@ -0,0 +1,14 @@
+#load "../Common/Product.csx"
+#r "Newtonsoft.Json"
+#r "Microsoft.Azure.WebJobs.Extensions.Sql"
+
+using System.Net;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Primitives;
+using Newtonsoft.Json;
+using Microsoft.Azure.WebJobs.Extensions.Sql;
+
+public static void Run(IReadOnlyList> changes, ILogger log)
+{
+ log.LogInformation("SQL Changes: " + Microsoft.Azure.WebJobs.Extensions.Sql.Utils.JsonSerializeObject(changes));
+}
\ No newline at end of file
diff --git a/test/Integration/test-java/src/main/java/com/function/Common/SqlChangeProductColumnTypes.java b/test/Integration/test-java/src/main/java/com/function/Common/SqlChangeProductColumnTypes.java
new file mode 100644
index 000000000..6bb222220
--- /dev/null
+++ b/test/Integration/test-java/src/main/java/com/function/Common/SqlChangeProductColumnTypes.java
@@ -0,0 +1,36 @@
+/**
+ * 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;
+
+public class SqlChangeProductColumnTypes {
+ private SqlChangeOperation Operation;
+ private ProductColumnTypes Item;
+
+ public SqlChangeProductColumnTypes() {
+ }
+
+ public SqlChangeProductColumnTypes(SqlChangeOperation operation, ProductColumnTypes item) {
+ this.Operation = operation;
+ this.Item = item;
+ }
+
+ public SqlChangeOperation getOperation() {
+ return Operation;
+ }
+
+ public void setOperation(SqlChangeOperation operation) {
+ this.Operation = operation;
+ }
+
+ public ProductColumnTypes getItem() {
+ return Item;
+ }
+
+ public void setItem(ProductColumnTypes item) {
+ this.Item = item;
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/test-java/src/main/java/com/function/ProductsColumnTypesTrigger.java b/test/Integration/test-java/src/main/java/com/function/ProductsColumnTypesTrigger.java
new file mode 100644
index 000000000..c05f76740
--- /dev/null
+++ b/test/Integration/test-java/src/main/java/com/function/ProductsColumnTypesTrigger.java
@@ -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.
+ */
+
+package com.function;
+
+import com.function.Common.SqlChangeProductColumnTypes;
+import com.google.gson.Gson;
+import com.microsoft.azure.functions.ExecutionContext;
+import com.microsoft.azure.functions.annotation.FunctionName;
+import com.microsoft.azure.functions.sql.annotation.SQLTrigger;
+
+import java.util.logging.Level;
+
+public class ProductsColumnTypesTrigger {
+ @FunctionName("ProductsColumnTypesTrigger")
+ public void run(
+ @SQLTrigger(
+ name = "changes",
+ tableName = "[dbo].[ProductsColumnTypes]",
+ connectionStringSetting = "SqlConnectionString")
+ SqlChangeProductColumnTypes[] changes,
+ ExecutionContext context) throws Exception {
+
+ context.getLogger().log(Level.INFO, "SQL Changes: " + new Gson().toJson(changes));
+ }
+}
\ No newline at end of file
diff --git a/test/Integration/test-js/ProductsColumnTypesTrigger/function.json b/test/Integration/test-js/ProductsColumnTypesTrigger/function.json
new file mode 100644
index 000000000..3285e3baf
--- /dev/null
+++ b/test/Integration/test-js/ProductsColumnTypesTrigger/function.json
@@ -0,0 +1,12 @@
+{
+ "bindings": [
+ {
+ "name": "changes",
+ "type": "sqlTrigger",
+ "direction": "in",
+ "tableName": "dbo.ProductsColumnTypes",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+ }
\ No newline at end of file
diff --git a/test/Integration/test-js/ProductsColumnTypesTrigger/index.js b/test/Integration/test-js/ProductsColumnTypesTrigger/index.js
new file mode 100644
index 000000000..5886e5c82
--- /dev/null
+++ b/test/Integration/test-js/ProductsColumnTypesTrigger/index.js
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See License.txt in the project root for license information.
+
+module.exports = async function (context, changes) {
+ context.log(`SQL Changes: ${JSON.stringify(changes)}`)
+}
\ No newline at end of file
diff --git a/test/Integration/test-powershell/ProductsColumnTypesTrigger/function.json b/test/Integration/test-powershell/ProductsColumnTypesTrigger/function.json
new file mode 100644
index 000000000..3285e3baf
--- /dev/null
+++ b/test/Integration/test-powershell/ProductsColumnTypesTrigger/function.json
@@ -0,0 +1,12 @@
+{
+ "bindings": [
+ {
+ "name": "changes",
+ "type": "sqlTrigger",
+ "direction": "in",
+ "tableName": "dbo.ProductsColumnTypes",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+ }
\ No newline at end of file
diff --git a/test/Integration/test-powershell/ProductsColumnTypesTrigger/run.ps1 b/test/Integration/test-powershell/ProductsColumnTypesTrigger/run.ps1
new file mode 100644
index 000000000..e8c4559d6
--- /dev/null
+++ b/test/Integration/test-powershell/ProductsColumnTypesTrigger/run.ps1
@@ -0,0 +1,9 @@
+# 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
+
+param($changes)
+
+$changesJson = $changes | ConvertTo-Json -Compress -AsArray
+Write-Host "SQL Changes: $changesJson"
\ No newline at end of file
diff --git a/test/Integration/test-python/ProductsColumnTypesTrigger/__init__.py b/test/Integration/test-python/ProductsColumnTypesTrigger/__init__.py
new file mode 100644
index 000000000..688c1e16c
--- /dev/null
+++ b/test/Integration/test-python/ProductsColumnTypesTrigger/__init__.py
@@ -0,0 +1,7 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+import logging
+
+def main(changes):
+ logging.info("SQL Changes: %s", changes)
diff --git a/test/Integration/test-python/ProductsColumnTypesTrigger/function.json b/test/Integration/test-python/ProductsColumnTypesTrigger/function.json
new file mode 100644
index 000000000..3285e3baf
--- /dev/null
+++ b/test/Integration/test-python/ProductsColumnTypesTrigger/function.json
@@ -0,0 +1,12 @@
+{
+ "bindings": [
+ {
+ "name": "changes",
+ "type": "sqlTrigger",
+ "direction": "in",
+ "tableName": "dbo.ProductsColumnTypes",
+ "connectionStringSetting": "SqlConnectionString"
+ }
+ ],
+ "disabled": false
+ }
\ No newline at end of file