Пример #1
0
        public RelationalDatabaseWriter.TableQuerySummary[] SimulateSqlReplicationSQLQueries(string strDocumentId, SqlReplicationConfig sqlReplication, bool performRolledbackTransaction, out Alert alert)
        {
            alert = null;
            RelationalDatabaseWriter.TableQuerySummary[] resutls = null;

            try
            {
                var stats = new SqlReplicationStatistics(sqlReplication.Name);
                var docs  = new List <JsonDocument>()
                {
                    Database.Documents.Get(strDocumentId, null)
                };
                var scriptResult = ApplyConversionScript(sqlReplication, docs);

                var connectionsDoc            = Database.Documents.Get(connectionsDocumentName, null);
                var sqlReplicationConnections = connectionsDoc.DataAsJson.JsonDeserialization <SqlReplicationConnections>();

                if (PrepareSqlReplicationConfig(sqlReplication, sqlReplication.Name, stats, sqlReplicationConnections, false, false))
                {
                    if (performRolledbackTransaction)
                    {
                        using (var writer = new RelationalDatabaseWriter(Database, sqlReplication, stats))
                        {
                            resutls = writer.RolledBackExecute(scriptResult).ToArray();
                        }
                    }
                    else
                    {
                        var simulatedwriter = new RelationalDatabaseWriterSimulator(Database, sqlReplication, stats);
                        resutls = new List <RelationalDatabaseWriter.TableQuerySummary>()
                        {
                            new RelationalDatabaseWriter.TableQuerySummary()
                            {
                                Commands = simulatedwriter.SimulateExecuteCommandText(scriptResult)
                                           .Select(x => new RelationalDatabaseWriter.TableQuerySummary.CommandData()
                                {
                                    CommandText = x
                                }).ToArray()
                            }
                        }.ToArray();
                    }
                }

                alert = stats.LastAlert;
            }
            catch (Exception e)
            {
                alert = new Alert()
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = SystemTime.UtcNow,
                    Message    = "Last SQL replication operation for " + sqlReplication.Name + " was failed",
                    Title      = "SQL replication error",
                    Exception  = e.ToString(),
                    UniqueKey  = "Sql Replication Error: " + sqlReplication.Name
                };
            }
            return(resutls);
        }
        public RelationalDatabaseWriterSimulator( DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
        {
            this.database = database;
            this.cfg = cfg;
            this.replicationStatistics = replicationStatistics;
            providerFactory = DbProviderFactories.GetFactory(cfg.FactoryName);
            commandBuilder = providerFactory.CreateCommandBuilder();
            if (SqlServerFactoryNames.Contains(cfg.FactoryName))
		    {
		        IsSqlServerFactoryType = true;
        }
        }
 public RelationalDatabaseWriterSimulator(DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
 {
     this.database = database;
     this.cfg      = cfg;
     this.replicationStatistics = replicationStatistics;
     providerFactory            = DbProviderFactories.GetFactory(cfg.FactoryName);
     commandBuilder             = providerFactory.CreateCommandBuilder();
     if (SqlServerFactoryNames.Contains(cfg.FactoryName))
     {
         IsSqlServerFactoryType = true;
     }
 }
        public RelationalDatabaseWriter(DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
        {
            this.database = database;
            this.cfg      = cfg;
            this.replicationStatistics = replicationStatistics;

            providerFactory = GetDbProviderFactory(cfg);

            commandBuilder = providerFactory.CreateCommandBuilder();
            connection     = providerFactory.CreateConnection();

            Debug.Assert(connection != null);
            Debug.Assert(commandBuilder != null);

            connection.ConnectionString = cfg.ConnectionString;

            if (SqlServerFactoryNames.Contains(cfg.FactoryName))
            {
                IsSqlServerFactoryType = true;
            }

            try
            {
                connection.Open();
            }
            catch (Exception e)
            {
                var message = "Sql Replication could not open connection to " + connection.ConnectionString;
                log.Error(message);
                database.AddAlert(new Alert
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = SystemTime.UtcNow,
                    Exception  = e.ToString(),
                    Title      = "Sql Replication could not open connection",
                    Message    = message,
                    UniqueKey  = "Sql Replication Connection Error: " + connection.ConnectionString
                });
                throw;
            }

            tx = connection.BeginTransaction();

            stringParserList      = GenerateStringParsers();
            sqlReplicationMetrics = database.StartupTasks.OfType <SqlReplicationTask>().FirstOrDefault().GetSqlReplicationMetricsManager(cfg);
        }
Пример #5
0
		public RelationalDatabaseWriter( DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
		{
			this.database = database;
			this.cfg = cfg;
			this.replicationStatistics = replicationStatistics;

			providerFactory = GetDbProviderFactory(cfg);

			commandBuilder = providerFactory.CreateCommandBuilder();
			connection = providerFactory.CreateConnection();

			Debug.Assert(connection != null);
			Debug.Assert(commandBuilder != null);

			connection.ConnectionString = cfg.ConnectionString;
            
		    if (SqlServerFactoryNames.Contains(cfg.FactoryName))
		    {
                IsSqlServerFactoryType = true;
		    }

			try
			{
				connection.Open();
			}
			catch (Exception e)
			{
				database.AddAlert(new Alert
				{
					AlertLevel = AlertLevel.Error,
					CreatedAt = SystemTime.UtcNow,
					Exception = e.ToString(),
					Title = "Sql Replication could not open connection",
					Message = "Sql Replication could not open connection to " + connection.ConnectionString,
					UniqueKey = "Sql Replication Connection Error: " + connection.ConnectionString
				});
				throw;
			}

			tx = connection.BeginTransaction();

            stringParserList = GenerateStringParsers();
            sqlReplicationMetrics = database.StartupTasks.OfType<SqlReplicationTask>().FirstOrDefault().GetSqlReplicationMetricsManager(cfg);
		}
        public ElasticsearchDestinationWriter(DocumentDatabase database, SqlReplicationConfig _cfg, SqlReplicationStatistics replicationStatistics)
		{
            var cfg = new ElasticsearchReplicationConfig(_cfg);

			this.database = database;
			this.cfg = cfg;
            this.targetIndexName = cfg.FactoryName.ToLowerInvariant(); // Elasticsearch requires all index names to be lowercased
			this.replicationStatistics = replicationStatistics;
            
            try
            {
                elasticsearchClient = cfg.GetElasticClient();
            }
            catch (UriFormatException e)
            {
                if (database != null)
                    database.AddAlert(new Alert
                    {
                        AlertLevel = AlertLevel.Error,
                        CreatedAt = SystemTime.UtcNow,
                        Exception = e.ToString(),
                        Title = "Invalid Elasticsearch URL provided",
                        Message = "Elasticsearch Replication could not parse one of the provided node URLs",
                        UniqueKey = "Elasticsearch Replication Connection Error: " + cfg.ConnectionString
                    });
            }
			catch (Exception e)
			{
			    if (database != null)
			        database.AddAlert(new Alert
			        {
			            AlertLevel = AlertLevel.Error,
			            CreatedAt = SystemTime.UtcNow,
			            Exception = e.ToString(),
			            Title = "Elasticsearch Replication could not open connection",
			            Message = "Elasticsearch Replication could not open connection to " + cfg.ConnectionString,
			            UniqueKey = "Elasticsearch Replication Connection Error: " + cfg.ConnectionString
			        });
				throw;
			}
		}
Пример #7
0
        public RelationalDatabaseWriter(DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
        {
            this.database = database;
            this.cfg      = cfg;
            this.replicationStatistics = replicationStatistics;

            providerFactory = GetDbProviderFactory(cfg);

            commandBuilder = providerFactory.CreateCommandBuilder();
            connection     = providerFactory.CreateConnection();

            Debug.Assert(connection != null);
            Debug.Assert(commandBuilder != null);

            connection.ConnectionString = cfg.ConnectionString;

            try
            {
                connection.Open();
            }
            catch (Exception e)
            {
                database.AddAlert(new Alert
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = SystemTime.UtcNow,
                    Exception  = e.ToString(),
                    Title      = "Sql Replication could not open connection",
                    Message    = "Sql Replication could not open connection to " + connection.ConnectionString,
                    UniqueKey  = "Sql Replication Connection Error: " + connection.ConnectionString
                });
                throw;
            }

            tx = connection.BeginTransaction();
        }
Пример #8
0
		public RelationalDatabaseWriter( DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
		{
			this.database = database;
			this.cfg = cfg;
			this.replicationStatistics = replicationStatistics;

			providerFactory = GetDbProviderFactory(cfg);

			commandBuilder = providerFactory.CreateCommandBuilder();
			connection = providerFactory.CreateConnection();

			Debug.Assert(connection != null);
			Debug.Assert(commandBuilder != null);

			connection.ConnectionString = cfg.ConnectionString;

			try
			{
				connection.Open();
			}
			catch (Exception e)
			{
				database.AddAlert(new Alert
				{
					AlertLevel = AlertLevel.Error,
					CreatedAt = SystemTime.UtcNow,
					Exception = e.ToString(),
					Title = "Sql Replication could not open connection",
					Message = "Sql Replication could not open connection to " + connection.ConnectionString,
					UniqueKey = "Sql Replication Connection Error: " + connection.ConnectionString
				});
				throw;
			}

			tx = connection.BeginTransaction();
		}
Пример #9
0
        private bool PrepareSqlReplicationConfig(SqlReplicationConfig cfg, string sqlReplicationConfigDocumentKey, SqlReplicationStatistics replicationStats, SqlReplicationConnections <SqlReplicationConnections.PredefinedSqlConnectionWithConfigurationOrigin> sqlReplicationConnections, bool writeToLog = true, bool validateSqlReplicationName = true)
        {
            if (validateSqlReplicationName && string.IsNullOrWhiteSpace(cfg.Name))
            {
                if (writeToLog)
                {
                    Log.Warn("Could not find name for sql replication document {0}, ignoring", sqlReplicationConfigDocumentKey);
                }
                replicationStats.LastAlert = new Alert
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = DateTime.UtcNow,
                    Title      = "Could not start replication",
                    Message    = string.Format("Could not find name for sql replication document {0}, ignoring", sqlReplicationConfigDocumentKey)
                };
                return(false);
            }
            if (string.IsNullOrWhiteSpace(cfg.PredefinedConnectionStringSettingName) == false)
            {
                var matchingConnection = sqlReplicationConnections.PredefinedConnections.FirstOrDefault(x => string.Compare(x.Name, cfg.PredefinedConnectionStringSettingName, StringComparison.InvariantCultureIgnoreCase) == 0);
                if (matchingConnection != null)
                {
                    cfg.ConnectionString = matchingConnection.ConnectionString;
                    cfg.FactoryName      = matchingConnection.FactoryName;
                }
                else
                {
                    if (writeToLog)
                    {
                        Log.Warn("Could not find predefined connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                 cfg.PredefinedConnectionStringSettingName,
                                 sqlReplicationConfigDocumentKey);
                    }
                    replicationStats.LastAlert = new Alert
                    {
                        AlertLevel = AlertLevel.Error,
                        CreatedAt  = DateTime.UtcNow,
                        Title      = "Could not start replication",
                        Message    = string.Format("Could not find predefined connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                                   cfg.PredefinedConnectionStringSettingName,
                                                   sqlReplicationConfigDocumentKey)
                    };
                    return(false);
                }
            }
            else if (string.IsNullOrWhiteSpace(cfg.ConnectionStringName) == false)
            {
                var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings[cfg.ConnectionStringName];
                if (connectionString == null)
                {
                    if (writeToLog)
                    {
                        Log.Warn("Could not find connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                 cfg.ConnectionStringName, sqlReplicationConfigDocumentKey);
                    }

                    replicationStats.LastAlert = new Alert
                    {
                        AlertLevel = AlertLevel.Error,
                        CreatedAt  = DateTime.UtcNow,
                        Title      = "Could not start replication",
                        Message    = string.Format("Could not find connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                                   cfg.ConnectionStringName,
                                                   sqlReplicationConfigDocumentKey)
                    };
                    return(false);
                }
                cfg.ConnectionString = connectionString.ConnectionString;
            }
            else if (string.IsNullOrWhiteSpace(cfg.ConnectionStringSettingName) == false)
            {
                var setting = Database.Configuration.Settings[cfg.ConnectionStringSettingName];
                if (string.IsNullOrWhiteSpace(setting))
                {
                    if (writeToLog)
                    {
                        Log.Warn("Could not find setting named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                 cfg.ConnectionStringSettingName,
                                 sqlReplicationConfigDocumentKey);
                    }
                    replicationStats.LastAlert = new Alert
                    {
                        AlertLevel = AlertLevel.Error,
                        CreatedAt  = DateTime.UtcNow,
                        Title      = "Could not start replication",
                        Message    = string.Format("Could not find setting named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
                                                   cfg.ConnectionStringSettingName,
                                                   sqlReplicationConfigDocumentKey)
                    };
                    return(false);
                }
            }
            return(true);
        }
Пример #10
0
        public RelationalDatabaseWriter.TableQuerySummary[] SimulateSqlReplicationSqlQueries(string strDocumentId, SqlReplicationConfig sqlReplication, bool performRolledbackTransaction, out Alert alert)
        {
            RelationalDatabaseWriter.TableQuerySummary[] resutls = null;

            try
            {
                var stats = new SqlReplicationStatistics(sqlReplication.Name, false);

                var jsonDocument = Database.Documents.Get(strDocumentId, null);
                JsonDocument.EnsureIdInMetadata(jsonDocument);
                var doc = jsonDocument.ToJson();
                doc[Constants.DocumentIdFieldName] = jsonDocument.Key;

                var docs = new List <ReplicatedDoc>
                {
                    new ReplicatedDoc
                    {
                        Document             = doc,
                        Etag                 = jsonDocument.Etag,
                        Key                  = jsonDocument.Key,
                        SerializedSizeOnDisk = jsonDocument.SerializedSizeOnDisk
                    }
                };
                var scriptResult = ApplyConversionScript(sqlReplication, docs, stats);

                var sqlReplicationConnections = Database.ConfigurationRetriever.GetConfigurationDocument <SqlReplicationConnections <SqlReplicationConnections.PredefinedSqlConnectionWithConfigurationOrigin> >(Constants.SqlReplication.SqlReplicationConnectionsDocumentName);

                if (PrepareSqlReplicationConfig(sqlReplication, sqlReplication.Name, stats, sqlReplicationConnections.MergedDocument, false, false))
                {
                    if (performRolledbackTransaction)
                    {
                        using (var writer = new RelationalDatabaseWriter(Database, sqlReplication, stats))
                        {
                            resutls = writer.RolledBackExecute(scriptResult).ToArray();
                        }
                    }
                    else
                    {
                        var simulatedwriter = new RelationalDatabaseWriterSimulator(Database, sqlReplication, stats);
                        resutls = new List <RelationalDatabaseWriter.TableQuerySummary>
                        {
                            new RelationalDatabaseWriter.TableQuerySummary
                            {
                                Commands = simulatedwriter.SimulateExecuteCommandText(scriptResult)
                                           .Select(x => new RelationalDatabaseWriter.TableQuerySummary.CommandData
                                {
                                    CommandText = x
                                }).ToArray()
                            }
                        }.ToArray();
                    }
                }

                alert = stats.LastAlert;
            }
            catch (Exception e)
            {
                alert = new Alert
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = SystemTime.UtcNow,
                    Message    = "Last SQL replication operation for " + sqlReplication.Name + " was failed",
                    Title      = "SQL replication error",
                    Exception  = e.ToString(),
                    UniqueKey  = "Sql Replication Error: " + sqlReplication.Name
                };
            }
            return(resutls);
        }
Пример #11
0
        private ConversionScriptResult ApplyConversionScript(SqlReplicationConfig cfg, IEnumerable <ReplicatedDoc> docs, SqlReplicationStatistics replicationStats)
        {
            var result = new ConversionScriptResult();

            foreach (var replicatedDoc in docs)
            {
                Database.WorkContext.CancellationToken.ThrowIfCancellationRequested();
                if (string.IsNullOrEmpty(cfg.RavenEntityName) == false)
                {
                    var entityName = replicatedDoc.Document[Constants.Metadata].Value <string>(Constants.RavenEntityName);
                    if (string.Equals(cfg.RavenEntityName, entityName, StringComparison.InvariantCultureIgnoreCase) == false)
                    {
                        continue;
                    }
                }

                var patcher = new SqlReplicationScriptedJsonPatcher(Database, result, cfg, replicatedDoc.Key);
                using (var scope = new SqlReplicationScriptedJsonPatcherOperationScope(Database))
                {
                    try
                    {
                        patcher.Apply(scope, replicatedDoc.Document, new ScriptedPatchRequest {
                            Script = cfg.Script
                        }, replicatedDoc.SerializedSizeOnDisk);

                        if (Log.IsDebugEnabled && patcher.Debug.Count > 0)
                        {
                            Log.Debug("Debug output for doc: {0} for script {1}:\r\n.{2}", replicatedDoc.Key, cfg.Name, string.Join("\r\n", patcher.Debug));

                            patcher.Debug.Clear();
                        }

                        replicationStats.ScriptSuccess();
                    }
                    catch (ParseException e)
                    {
                        replicationStats.MarkScriptAsInvalid(Database, cfg.Script);

                        Log.WarnException("Could not parse SQL Replication script for " + cfg.Name, e);

                        return(result);
                    }
                    catch (Exception diffExceptionName)
                    {
                        replicationStats.RecordScriptError(Database, diffExceptionName);
                        Log.WarnException("Could not process SQL Replication script for " + cfg.Name + ", skipping document: " + replicatedDoc.Key, diffExceptionName);
                    }
                }
            }
            return(result);
        }
Пример #12
0
        public RelationalDatabaseWriter(DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
        {
            this.database = database;
            this.cfg      = cfg;
            this.replicationStatistics = replicationStatistics;

            providerFactory = GetDbProviderFactory(cfg);

            commandBuilder = providerFactory.CreateCommandBuilder();
            connection     = providerFactory.CreateConnection();

            Debug.Assert(connection != null);
            Debug.Assert(commandBuilder != null);

            connection.ConnectionString = cfg.ConnectionString;

            try
            {
                connection.Open();
            }
            catch (Exception e)
            {
                database.AddAlert(new Alert
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt  = SystemTime.UtcNow,
                    Exception  = e.ToString(),
                    Title      = "Sql Replication could not open connection",
                    Message    = "Sql Replication could not open connection to " + connection.ConnectionString,
                    UniqueKey  = "Sql Replication Connection Error: " + connection.ConnectionString
                });
                throw;
            }

            tx = connection.BeginTransaction();

            stringParserList = new List <Func <DbParameter, string, bool> > {
                (colParam, value) => {
                    if (char.IsDigit(value[0]))
                    {
                        DateTime dateTime;
                        if (DateTime.TryParseExact(value, Default.OnlyDateTimeFormat, CultureInfo.InvariantCulture,
                                                   DateTimeStyles.RoundtripKind, out dateTime))
                        {
                            switch (providerFactory.GetType( ).Name)
                            {
                            case "MySqlClientFactory":
                                colParam.Value = dateTime.ToString("yyyy-MM-dd HH:mm:ss.ffffff");
                                break;

                            default:
                                colParam.Value = dateTime;
                                break;
                            }
                            return(true);
                        }
                    }
                    return(false);
                },
                (colParam, value) => {
                    if (char.IsDigit(value[0]))
                    {
                        DateTimeOffset dateTimeOffset;
                        if (DateTimeOffset.TryParseExact(value, Default.DateTimeFormatsToRead, CultureInfo.InvariantCulture,
                                                         DateTimeStyles.RoundtripKind, out dateTimeOffset))
                        {
                            switch (providerFactory.GetType( ).Name)
                            {
                            case "MySqlClientFactory":
                                colParam.Value = dateTimeOffset.ToUniversalTime().ToString("yyyy-MM-dd HH:mm:ss.ffffff");
                                break;

                            default:
                                colParam.Value = dateTimeOffset;
                                break;
                            }
                            return(true);
                        }
                    }
                    return(false);
                }
            };
        }
Пример #13
0
		private bool WriteToRelationalDatabase(SqlReplicationConfig cfg, DbProviderFactory providerFactory, Dictionary<string, List<ItemToReplicate>> dictionary, SqlReplicationStatistics replicationStatistics)
		{
			using (var commandBuilder = providerFactory.CreateCommandBuilder())
			using (var connection = providerFactory.CreateConnection())
			{
				Debug.Assert(connection != null);
				Debug.Assert(commandBuilder != null);
				connection.ConnectionString = cfg.ConnectionString;
				try
				{
				connection.Open();
				}
				catch (Exception e)
				{
					Database.AddAlert(new Alert
					{
						AlertLevel = AlertLevel.Error,
						CreatedAt = SystemTime.UtcNow,
						Exception = e.ToString(),
						Title = "Sql Replication could not open connection",
						Message = "Sql Replication could not open connection to " + connection.ConnectionString,
						UniqueKey = "Sql Replication Connection Error: " + connection.ConnectionString
					});
					throw;
				}
				bool hadErrors = false;
				using (var tx = connection.BeginTransaction())
				{
					foreach (var kvp in dictionary)
					{
						// first, delete all the rows that might already exist there
						foreach (var itemToReplicate in kvp.Value)
						{
							using (var cmd = connection.CreateCommand())
							{
								cmd.Transaction = tx;
								var dbParameter = cmd.CreateParameter();
								dbParameter.ParameterName = GetParameterName(providerFactory, commandBuilder, itemToReplicate.PkName);
								cmd.Parameters.Add(dbParameter);
								dbParameter.Value = itemToReplicate.DocumentId;
								cmd.CommandText = string.Format("DELETE FROM {0} WHERE {1} = {2}",
								                                commandBuilder.QuoteIdentifier(kvp.Key),
								                                commandBuilder.QuoteIdentifier(itemToReplicate.PkName),
								                                dbParameter.ParameterName
									);
								try
								{
									cmd.ExecuteNonQuery();
								}
								catch (Exception e)
								{
									log.WarnException("Failure to replicate changes to relational database for: " + cfg.Name + ", will continue trying." + Environment.NewLine + cmd.CommandText, e);
									replicationStatistics.RecordWriteError(e, Database);
									hadErrors = true;
								}
							}
						}

						foreach (var itemToReplicate in kvp.Value)
						{
							using (var cmd = connection.CreateCommand())
							{
								cmd.Transaction = tx;

								var sb = new StringBuilder("INSERT INTO ")
									.Append(commandBuilder.QuoteIdentifier(kvp.Key))
									.Append(" (")
									.Append(commandBuilder.QuoteIdentifier(itemToReplicate.PkName))
									.Append(", ");
								foreach (var column in itemToReplicate.Columns)
								{
									if (column.Key == itemToReplicate.PkName)
										continue;
									sb.Append(commandBuilder.QuoteIdentifier(column.Key)).Append(", ");
								}
								sb.Length = sb.Length - 2;

								var pkParam = cmd.CreateParameter();
								pkParam.ParameterName = GetParameterName(providerFactory, commandBuilder, itemToReplicate.PkName);
								pkParam.Value = itemToReplicate.DocumentId;
								cmd.Parameters.Add(pkParam);

								sb.Append(") \r\nVALUES (")
								  .Append(GetParameterName(providerFactory, commandBuilder, itemToReplicate.PkName))
								  .Append(", ");

								foreach (var column in itemToReplicate.Columns)
								{
									if (column.Key == itemToReplicate.PkName)
										continue;
									var colParam = cmd.CreateParameter();
									colParam.ParameterName = column.Key;
									SetParamValue(colParam, column.Value);
									cmd.Parameters.Add(colParam);
									sb.Append(GetParameterName(providerFactory, commandBuilder, column.Key)).Append(", ");
								}
								sb.Length = sb.Length - 2;
								sb.Append(")");
								cmd.CommandText = sb.ToString();
								try
								{
									cmd.ExecuteNonQuery();
								}
								catch (Exception e)
								{
									log.WarnException("Failure to replicate changes to relational database for: " + cfg.Name + ", will continue trying." + Environment.NewLine + cmd.CommandText, e);
									replicationStatistics.RecordWriteError(e, Database);
									hadErrors = true;
								}
							}
						}
					}
					tx.Commit();
				}
				return hadErrors == false;
			}
		}
Пример #14
0
		private bool PrepareSqlReplicationConfig(SqlReplicationConfig cfg, string sqlReplicationConfigDocumentKey, SqlReplicationStatistics replicationStats, SqlReplicationConnections sqlReplicationConnections, bool writeToLog = true, bool validateSqlReplicationName = true)
		{
			if (validateSqlReplicationName && string.IsNullOrWhiteSpace(cfg.Name))
			{
				if (writeToLog)
					Log.Warn("Could not find name for sql replication document {0}, ignoring", sqlReplicationConfigDocumentKey);
				replicationStats.LastAlert = new Alert
				{
					AlertLevel = AlertLevel.Error,
					CreatedAt = DateTime.UtcNow,
					Title = "Could not start replication",
					Message = string.Format("Could not find name for sql replication document {0}, ignoring", sqlReplicationConfigDocumentKey)
				};
				return false;
			}
			if (string.IsNullOrWhiteSpace(cfg.PredefinedConnectionStringSettingName) == false)
			{
				var matchingConnection = sqlReplicationConnections.PredefinedConnections.FirstOrDefault(x => string.Compare(x.Name, cfg.PredefinedConnectionStringSettingName, StringComparison.InvariantCultureIgnoreCase) == 0);
				if (matchingConnection != null)
				{
					cfg.ConnectionString = matchingConnection.ConnectionString;
					cfg.FactoryName = matchingConnection.FactoryName;
				}
				else
				{
					if (writeToLog)
						Log.Warn("Could not find predefined connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
							cfg.PredefinedConnectionStringSettingName,
							sqlReplicationConfigDocumentKey);
					replicationStats.LastAlert = new Alert
					{
						AlertLevel = AlertLevel.Error,
						CreatedAt = DateTime.UtcNow,
						Title = "Could not start replication",
						Message = string.Format("Could not find predefined connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
							cfg.PredefinedConnectionStringSettingName,
							sqlReplicationConfigDocumentKey)
					};
					return false;
				}
			}
			else if (string.IsNullOrWhiteSpace(cfg.ConnectionStringName) == false)
			{
				var connectionString = ConfigurationManager.ConnectionStrings[cfg.ConnectionStringName];
				if (connectionString == null)
				{
					if (writeToLog)
						Log.Warn("Could not find connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
							cfg.ConnectionStringName, sqlReplicationConfigDocumentKey);

					replicationStats.LastAlert = new Alert
					{
						AlertLevel = AlertLevel.Error,
						CreatedAt = DateTime.UtcNow,
						Title = "Could not start replication",
						Message = string.Format("Could not find connection string named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
							cfg.ConnectionStringName,
							sqlReplicationConfigDocumentKey)
					};
					return false;
				}
				cfg.ConnectionString = connectionString.ConnectionString;
			}
			else if (string.IsNullOrWhiteSpace(cfg.ConnectionStringSettingName) == false)
			{
				var setting = Database.Configuration.Settings[cfg.ConnectionStringSettingName];
				if (string.IsNullOrWhiteSpace(setting))
				{
					if (writeToLog)
						Log.Warn("Could not find setting named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
			cfg.ConnectionStringSettingName,
			sqlReplicationConfigDocumentKey);
					replicationStats.LastAlert = new Alert
					{
						AlertLevel = AlertLevel.Error,
						CreatedAt = DateTime.UtcNow,
						Title = "Could not start replication",
						Message = string.Format("Could not find setting named '{0}' for sql replication config: {1}, ignoring sql replication setting.",
							cfg.ConnectionStringSettingName,
							sqlReplicationConfigDocumentKey)
					};
					return false;
				}
			}
			return true;
		}
Пример #15
0
		public RelationalDatabaseWriter.TableQuerySummary[] SimulateSqlReplicationSqlQueries(string strDocumentId, SqlReplicationConfig sqlReplication, bool performRolledbackTransaction, out Alert alert)
		{
			RelationalDatabaseWriter.TableQuerySummary[] resutls = null;

			try
			{
				var stats = new SqlReplicationStatistics(sqlReplication.Name, false);

				var jsonDocument = Database.Documents.Get(strDocumentId, null);
				JsonDocument.EnsureIdInMetadata(jsonDocument);
				var doc = jsonDocument.ToJson();
				doc[Constants.DocumentIdFieldName] = jsonDocument.Key;

				var docs = new List<ReplicatedDoc>
                           {
	                           new ReplicatedDoc
	                           {
		                           Document = doc,
								   Etag = jsonDocument.Etag,
								   Key = jsonDocument.Key,
								   SerializedSizeOnDisk = jsonDocument.SerializedSizeOnDisk
	                           }
                           };
				var scriptResult = ApplyConversionScript(sqlReplication, docs, stats);

				var connectionsDoc = Database.Documents.Get(Constants.RavenSqlReplicationConnectionsDocumentName, null);
				var sqlReplicationConnections = connectionsDoc != null ? connectionsDoc.DataAsJson.JsonDeserialization<SqlReplicationConnections>() : new SqlReplicationConnections();

				if (PrepareSqlReplicationConfig(sqlReplication, sqlReplication.Name, stats, sqlReplicationConnections, false, false))
				{
					if (performRolledbackTransaction)
					{
						using (var writer = new RelationalDatabaseWriter(Database, sqlReplication, stats))
						{
							resutls = writer.RolledBackExecute(scriptResult).ToArray();
						}
					}
					else
					{
						var simulatedwriter = new RelationalDatabaseWriterSimulator(Database, sqlReplication, stats);
						resutls = new List<RelationalDatabaseWriter.TableQuerySummary>
                        {
                            new RelationalDatabaseWriter.TableQuerySummary
                            {
                                Commands = simulatedwriter.SimulateExecuteCommandText(scriptResult)
                                    .Select(x => new RelationalDatabaseWriter.TableQuerySummary.CommandData
                                    {
                                        CommandText = x
                                    }).ToArray()
                            }
                        }.ToArray();


					}
				}

				alert = stats.LastAlert;
			}
			catch (Exception e)
			{
				alert = new Alert
				{
					AlertLevel = AlertLevel.Error,
					CreatedAt = SystemTime.UtcNow,
					Message = "Last SQL replication operation for " + sqlReplication.Name + " was failed",
					Title = "SQL replication error",
					Exception = e.ToString(),
					UniqueKey = "Sql Replication Error: " + sqlReplication.Name
				};
			}
			return resutls;
		}
Пример #16
0
		private ConversionScriptResult ApplyConversionScript(SqlReplicationConfig cfg, IEnumerable<ReplicatedDoc> docs, SqlReplicationStatistics replicationStats)
		{
			var result = new ConversionScriptResult();
			foreach (var replicatedDoc in docs)
			{
				Database.WorkContext.CancellationToken.ThrowIfCancellationRequested();
				if (string.IsNullOrEmpty(cfg.RavenEntityName) == false)
				{
					var entityName = replicatedDoc.Document[Constants.Metadata].Value<string>(Constants.RavenEntityName);
					if (string.Equals(cfg.RavenEntityName, entityName, StringComparison.InvariantCultureIgnoreCase) == false)
						continue;
				}

				var patcher = new SqlReplicationScriptedJsonPatcher(Database, result, cfg, replicatedDoc.Key);
				using (var scope = new SqlReplicationScriptedJsonPatcherOperationScope(Database))
				{
					try
					{
						patcher.Apply(scope, replicatedDoc.Document, new ScriptedPatchRequest { Script = cfg.Script }, replicatedDoc.SerializedSizeOnDisk);

						if (Log.IsDebugEnabled && patcher.Debug.Count > 0)
						{
							Log.Debug("Debug output for doc: {0} for script {1}:\r\n.{2}", replicatedDoc.Key, cfg.Name, string.Join("\r\n", patcher.Debug));

							patcher.Debug.Clear();
						}

						replicationStats.ScriptSuccess();
					}
					catch (ParseException e)
					{
						replicationStats.MarkScriptAsInvalid(Database, cfg.Script);

						Log.WarnException("Could not parse SQL Replication script for " + cfg.Name, e);

						return result;
					}
					catch (Exception diffExceptionName)
					{
						replicationStats.RecordScriptError(Database, diffExceptionName);
						Log.WarnException("Could not process SQL Replication script for " + cfg.Name + ", skipping document: " + replicatedDoc.Key, diffExceptionName);
					}
				}
			}
			return result;
		}
Пример #17
0
		public RelationalDatabaseWriter( DocumentDatabase database, SqlReplicationConfig cfg, SqlReplicationStatistics replicationStatistics)
		{
			this.database = database;
			this.cfg = cfg;
			this.replicationStatistics = replicationStatistics;

			providerFactory = GetDbProviderFactory(cfg);

			commandBuilder = providerFactory.CreateCommandBuilder();
			connection = providerFactory.CreateConnection();

			Debug.Assert(connection != null);
			Debug.Assert(commandBuilder != null);

			connection.ConnectionString = cfg.ConnectionString;

			try
			{
				connection.Open();
			}
			catch (Exception e)
			{
				database.AddAlert(new Alert
				{
					AlertLevel = AlertLevel.Error,
					CreatedAt = SystemTime.UtcNow,
					Exception = e.ToString(),
					Title = "Sql Replication could not open connection",
					Message = "Sql Replication could not open connection to " + connection.ConnectionString,
					UniqueKey = "Sql Replication Connection Error: " + connection.ConnectionString
				});
				throw;
			}

			tx = connection.BeginTransaction();

			stringParserList = new List<Func<DbParameter, string, bool>> { 
				(colParam, value) => {
					if( char.IsDigit( value[ 0 ] ) ) {
							DateTime dateTime;
							if (DateTime.TryParseExact(value, Default.OnlyDateTimeFormat, CultureInfo.InvariantCulture,
														DateTimeStyles.RoundtripKind, out dateTime))
							{
								switch( providerFactory.GetType( ).Name ) {
									case "MySqlClientFactory":
										colParam.Value = dateTime.ToString( "yyyy-MM-dd HH:mm:ss.ffffff" );
										break;
									default:
										colParam.Value = dateTime;
										break;
								}
								return true;
							}
					}
					return false;
				},
				(colParam, value) => {
					if( char.IsDigit( value[ 0 ] ) ) {
						DateTimeOffset dateTimeOffset;
						if( DateTimeOffset.TryParseExact( value, Default.DateTimeFormatsToRead, CultureInfo.InvariantCulture,
														 DateTimeStyles.RoundtripKind, out dateTimeOffset ) ) {
							switch( providerFactory.GetType( ).Name ) {
								case "MySqlClientFactory":
									colParam.Value = dateTimeOffset.ToUniversalTime().ToString( "yyyy-MM-dd HH:mm:ss.ffffff" );
									break;
								default:
									colParam.Value = dateTimeOffset;
									break;
							}
							return true;
						}
					}
					return false;
				}
			};
		}
Пример #18
0
        private bool WriteToRelationalDatabase(SqlReplicationConfig cfg, DbProviderFactory providerFactory, Dictionary<string, List<ItemToReplicate>> dictionary, SqlReplicationStatistics replicationStatistics)
        {
            using (var commandBuilder = providerFactory.CreateCommandBuilder())
            using (var connection = providerFactory.CreateConnection())
            {
                Debug.Assert(connection != null);
                Debug.Assert(commandBuilder != null);
                connection.ConnectionString = cfg.ConnectionString;
                try
                {
                    connection.Open();
                }
                catch (Exception e)
                {
                    Database.AddAlert(new Alert
                    {
                        AlertLevel = AlertLevel.Error,
                        CreatedAt = SystemTime.UtcNow,
                        Exception = e.ToString(),
                        Title = "Sql Replication could not open connection",
                        Message = "Sql Replication could not open connection to " + connection.ConnectionString,
                        UniqueKey = "Sql Replication Connection Error: " + connection.ConnectionString
                    });
                    throw;
                }
                bool hadErrors = false;
                using (var tx = connection.BeginTransaction())
                {
                    const string cmdText = "DELETE FROM {0} WHERE {1} IN ({2})";

                    foreach (var kvp in dictionary)
                    {

                        // array of ids to delete
                        List<string> ids = kvp.Value.Select(x => x.DocumentId).ToList();

                        foreach (var partitionOfIds in ids.Partition(1000))
                        {
                            using (var deleteCmd = connection.CreateCommand())
                            {
                                // create an array of param names to store our ids (@id1, @id2 etc)
                                string[] paramNames = partitionOfIds.Select(
                                    (s, i) => "@id" + i.ToString()
                                    ).ToArray();

                                // add a parameter for each id to our command
                                string inClause = string.Join(",", paramNames);

                                for (int i = 0; i < paramNames.Length; i++)
                                {
                                    var param = deleteCmd.CreateParameter();
                                    param.ParameterName = paramNames[i];
                                    param.Value = partitionOfIds[i];
                                    deleteCmd.Parameters.Add(param);
                                }

                                deleteCmd.Transaction = tx;

                                deleteCmd.CommandText = string.Format(cmdText,
                                                                        commandBuilder.QuoteIdentifier(kvp.Key),
                                                                        commandBuilder.QuoteIdentifier(
                                                                            kvp.Value[0].PkName),
                                                                        inClause);
                                try
                                {
                                    deleteCmd.ExecuteNonQuery();
                                }
                                catch (Exception e)
                                {
                                    log.WarnException(
                                        "Failure to replicate changes to relational database for: " + cfg.Name +
                                        " (delete), will continue trying." + Environment.NewLine +
                                        deleteCmd.CommandText, e);
                                    replicationStatistics.RecordWriteError(e, Database);
                                    hadErrors = true;
                                }
                            }
                        }

                        foreach (var itemToReplicate in kvp.Value)
                        {
                            using (var cmd = connection.CreateCommand())
                            {
                                cmd.Transaction = tx;

                                var sb = new StringBuilder("INSERT INTO ")
                                    .Append(commandBuilder.QuoteIdentifier(kvp.Key))
                                    .Append(" (")
                                    .Append(commandBuilder.QuoteIdentifier(itemToReplicate.PkName))
                                    .Append(", ");
                                foreach (var column in itemToReplicate.Columns)
                                {
                                    if (column.Key == itemToReplicate.PkName)
                                        continue;
                                    sb.Append(commandBuilder.QuoteIdentifier(column.Key)).Append(", ");
                                }
                                sb.Length = sb.Length - 2;

                                var pkParam = cmd.CreateParameter();
                                pkParam.ParameterName = GetParameterName(providerFactory, commandBuilder, itemToReplicate.PkName);
                                pkParam.Value = itemToReplicate.DocumentId;
                                cmd.Parameters.Add(pkParam);

                                sb.Append(") \r\nVALUES (")
                                  .Append(GetParameterName(providerFactory, commandBuilder, itemToReplicate.PkName))
                                  .Append(", ");

                                foreach (var column in itemToReplicate.Columns)
                                {
                                    if (column.Key == itemToReplicate.PkName)
                                        continue;
                                    var colParam = cmd.CreateParameter();
                                    colParam.ParameterName = column.Key;
                                    SetParamValue(colParam, column.Value);
                                    cmd.Parameters.Add(colParam);
                                    sb.Append(GetParameterName(providerFactory, commandBuilder, column.Key)).Append(", ");
                                }
                                sb.Length = sb.Length - 2;
                                sb.Append(")");
                                cmd.CommandText = sb.ToString();
                                try
                                {
                                    cmd.ExecuteNonQuery();
                                }
                                catch (Exception e)
                                {
                                    log.WarnException("Failure to replicate changes to relational database for: " + cfg.Name + " (insert), will continue trying." + Environment.NewLine + cmd.CommandText, e);
                                    replicationStatistics.RecordWriteError(e, Database);
                                    hadErrors = true;
                                }
                            }
                        }
                    }
                    tx.Commit();
                }
                return hadErrors == false;
            }
        }
Пример #19
0
        public RelationalDatabaseWriter.TableQuerySummary[] SimulateSqlReplicationSQLQueries(string strDocumentId, SqlReplicationConfig sqlReplication, bool performRolledbackTransaction, out Alert alert)
        {
            alert = null;
            RelationalDatabaseWriter.TableQuerySummary[] resutls = null;
            
            try
            {
                var stats = new SqlReplicationStatistics(sqlReplication.Name);
                var docs = new List<JsonDocument>() { Database.Documents.Get(strDocumentId, null) };
                var scriptResult = ApplyConversionScript(sqlReplication, docs);

                var connectionsDoc = Database.Documents.Get(connectionsDocumentName, null);
                var sqlReplicationConnections = connectionsDoc.DataAsJson.JsonDeserialization<SqlReplicationConnections>();

                if (PrepareSqlReplicationConfig( sqlReplication, sqlReplication.Name,  stats, sqlReplicationConnections, false,false))
                {
                    if (performRolledbackTransaction)
                    {
                        using (var writer = new RelationalDatabaseWriter(Database, sqlReplication, stats))
                        {
                            resutls = writer.RolledBackExecute(scriptResult).ToArray();
                        }
                    }
                    else
                    {
                        var simulatedwriter = new RelationalDatabaseWriterSimulator(Database, sqlReplication, stats);
                        resutls = new List<RelationalDatabaseWriter.TableQuerySummary>()
                        {
                            new RelationalDatabaseWriter.TableQuerySummary()
                            {
                                Commands = simulatedwriter.SimulateExecuteCommandText(scriptResult)
                                    .Select(x => new RelationalDatabaseWriter.TableQuerySummary.CommandData()
                                    {
                                        CommandText = x
                                    }).ToArray()
                            }
                        }.ToArray();


                    }
                }

                alert = stats.LastAlert;
            }
            catch (Exception e)
            {
                alert = new Alert()
                {
                    AlertLevel = AlertLevel.Error,
                    CreatedAt = SystemTime.UtcNow,
                    Message = "Last SQL replication operation for " + sqlReplication.Name + " was failed",
                    Title = "SQL replication error",
                    Exception = e.ToString(),
                    UniqueKey = "Sql Replication Error: " + sqlReplication.Name
                };
            }
            return resutls;
        }