in src/TriggerBinding/SqlTriggerListener.cs [320:363]
private async Task<long> CreateGlobalStateTableAsync(SqlConnection connection, SqlTransaction transaction, CancellationToken cancellationToken)
{
string createGlobalStateTableQuery = $@"
{AppLockStatements}
IF OBJECT_ID(N'{GlobalStateTableName}', 'U') IS NULL
CREATE TABLE {GlobalStateTableName} (
UserFunctionID char(16) NOT NULL,
UserTableID int NOT NULL,
LastSyncVersion bigint NOT NULL,
LastAccessTime Datetime NOT NULL DEFAULT GETUTCDATE(),
PRIMARY KEY (UserFunctionID, UserTableID)
);
ELSE IF NOT EXISTS(SELECT 1 FROM sys.columns WHERE Name = N'LastAccessTime'
AND Object_ID = Object_ID(N'{GlobalStateTableName}'))
ALTER TABLE {GlobalStateTableName} ADD LastAccessTime Datetime NOT NULL DEFAULT GETUTCDATE();
";
using (var createGlobalStateTableCommand = new SqlCommand(createGlobalStateTableQuery, connection, transaction))
{
var stopwatch = Stopwatch.StartNew();
try
{
await createGlobalStateTableCommand.ExecuteNonQueryAsyncWithLogging(this._logger, cancellationToken);
}
catch (Exception ex)
{
TelemetryInstance.TrackException(TelemetryErrorName.CreateGlobalStateTable, ex, this._telemetryProps);
var sqlEx = ex as SqlException;
if (sqlEx?.Number == ObjectAlreadyExistsErrorNumber)
{
// This generally shouldn't happen since we check for its existence in the statement but occasionally
// a race condition can make it so that multiple instances will try and create the schema at once.
// In that case we can just ignore the error since all we care about is that the schema exists at all.
this._logger.LogWarning($"Failed to create global state table '{GlobalStateTableName}'. Exception message: {ex.Message} This is informational only, function startup will continue as normal.");
}
else
{
throw;
}
}
return stopwatch.ElapsedMilliseconds;
}
}