Exemple #1
0
        public void SetToRecommendedPlan()
        {
            //get an extraction category based on it's current extractability
            ExtractionCategoryIfAny = GetMaxExtractionCategoryIfAny();

            if (SpecialFieldNames.IsHicPrefixed(ColumnInfo))
            {
                Plan = Plan.Drop;//suggest dropping hic_ fields
            }
            else
            if (ColumnInfo.IsPrimaryKey || IsInvolvedInLookups() || IsInvolvedInJoins())
            {
                Plan = Plan.PassThroughUnchanged;     //if it's involved in lookups, joins or is a primary key
            }
            else
            if (ExtractionCategoryIfAny == null)         //if it isn't extractable
            {
                Plan = Plan.Drop;
            }
            else
            {
                Plan = Plan.PassThroughUnchanged;         //it is extractable but not special
            }
            //if theres an associated ANOTable with a different ColumnInfo with the same name e.g. chi=>ANOChi in another dataset that was already anonymised
            MakeANOTableSuggestionIfApplicable();
        }
        private string AppendRelevantOrderBySql(string sql, IResolveDuplication col)
        {
            string colname = _querySyntaxHelper.EnsureWrapped(col.GetRuntimeName(LoadStage.AdjustRaw));

            string direction = col.DuplicateRecordResolutionIsAscending ? " ASC" : " DESC";

            //dont bother adding these because they are hic generated
            if (SpecialFieldNames.IsHicPrefixed(colname))
            {
                return(sql);
            }

            ValueType valueType = GetDataType(col.Data_type);

            if (valueType == ValueType.CharacterString)
            {
                //character strings are compared first by LENGTH (to prefer longer data)
                //then by alphabetical comparison to prefer things towards the start of the alphabet (because this makes sense?!)
                return
                    (sql +
                     "LEN(ISNULL(" + colname + "," + GetNullSubstituteForComparisonsWithDataType(col.Data_type, true) + "))" + direction + "," + Environment.NewLine +
                     "ISNULL(" + colname + "," + GetNullSubstituteForComparisonsWithDataType(col.Data_type, true) + ")" + direction + "," + Environment.NewLine);
            }

            return(sql + "ISNULL(" + colname + "," + GetNullSubstituteForComparisonsWithDataType(col.Data_type, true) + ")" + direction + "," + Environment.NewLine);
        }
Exemple #3
0
        public void AssignFieldsForProcessing(DiscoveredColumn field, List <DiscoveredColumn> fieldsToDiff, List <DiscoveredColumn> fieldsToUpdate)
        {
            if (IgnoreColumnInfo(field))
            {
                return;
            }

            if (Ignore(field))
            {
                return;
            }

            //it is a hic internal field but not one of the overwritten, standard ones
            if (SpecialFieldNames.IsHicPrefixed(field)
                ||
                UpdateOnly(field))
            {
                fieldsToUpdate.Add(field);
            }
            else
            {
                //it is not a hic internal field
                fieldsToDiff.Add(field);
                fieldsToUpdate.Add(field);
            }
        }
Exemple #4
0
        private void ConfirmStagingAndLiveHaveSameColumns(string tableName, DiscoveredColumn[] stagingCols, DiscoveredColumn[] liveCols, bool requireSameNumberAndOrder, ICheckNotifier notifier)
        {
            //in LIVE but not STAGING
            foreach (var missingColumn in liveCols.Select(c => c.GetRuntimeName()).Except(stagingCols.Select(c => c.GetRuntimeName())))
            {
                //column is in live but not in staging, but it is hic_
                if (SpecialFieldNames.IsHicPrefixed(missingColumn)) //this is permitted
                {
                    continue;
                }
                else
                {
                    notifier.OnCheckPerformed(new CheckEventArgs(
                                                  "Column " + missingColumn + " is missing from STAGING", CheckResult.Fail, null));
                }
            }

            //in STAGING but not LIVE
            foreach (var missingColumn in stagingCols.Except(liveCols))
            {
                notifier.OnCheckPerformed(new CheckEventArgs(
                                              "Column " + missingColumn + " is in STAGING but not LIVE", CheckResult.Fail, null));
            }



            if (requireSameNumberAndOrder)
            {
                bool passedColumnOrderCheck = true;

                if (stagingCols.Length != liveCols.Length)
                {
                    notifier.OnCheckPerformed(new CheckEventArgs(
                                                  "Column count mismatch between staging and live in table " + tableName, CheckResult.Fail, null));
                    passedColumnOrderCheck = false;
                }
                else
                {
                    //check they are in the same order
                    for (int i = 0; i < stagingCols.Length; i++)
                    {
                        if (!stagingCols[i].Equals(liveCols[i]))
                        {
                            notifier.OnCheckPerformed(new CheckEventArgs(
                                                          "Column name/order mismatch between staging and live in table " + tableName +
                                                          ", column " + i + " is " + stagingCols[i] + " in staging but is " + liveCols[i] +
                                                          " in live.", CheckResult.Fail, null));
                            passedColumnOrderCheck = false;
                            break;
                        }
                    }
                }

                if (passedColumnOrderCheck)
                {
                    notifier.OnCheckPerformed(new CheckEventArgs("Column order match confirmed between staging and live on table " + tableName, CheckResult.Success, null));
                }
            }
        }
Exemple #5
0
        public void CloneTable(DiscoveredDatabase srcDatabaseInfo, DiscoveredDatabase destDatabaseInfo, DiscoveredTable sourceTable, string destTableName, bool dropHICColumns, bool dropIdentityColumns, bool allowNulls, PreLoadDiscardedColumn[] dillutionColumns)
        {
            if (!sourceTable.Exists())
            {
                throw new Exception("Table " + sourceTable + " does not exist on " + srcDatabaseInfo);
            }


            //new table will start with the same name as the as the old scripted one
            DiscoveredTable newTable = destDatabaseInfo.ExpectTable(destTableName);

            var sql = sourceTable.ScriptTableCreation(allowNulls, allowNulls, false /*False because we want to drop these columns entirely not just flip to int*/, newTable);

            using (var con = destDatabaseInfo.Server.GetConnection())
            {
                con.Open();
                var cmd = destDatabaseInfo.Server.GetCommand(sql, con);
                cmd.ExecuteNonQuery();
            }

            if (!newTable.Exists())
            {
                throw new Exception("Table '" + newTable + "' not found in " + destDatabaseInfo + " despite running table creation SQL!");
            }

            foreach (DiscoveredColumn column in newTable.DiscoverColumns())
            {
                bool drop    = false;
                var  colName = column.GetRuntimeName();

                if (column.IsAutoIncrement)
                {
                    drop = true;
                }

                if (SpecialFieldNames.IsHicPrefixed(colName) && dropHICColumns)
                {
                    drop = true;
                }

                //drop the data load run ID field and validFrom fields, we don't need them in STAGING or RAW, it will be hard coded in the MERGE migration with a fixed value anyway.
                if (colName.Equals(SpecialFieldNames.DataLoadRunID) || colName.Equals(SpecialFieldNames.ValidFrom))
                {
                    drop = true;
                }

                var dillution = dillutionColumns.SingleOrDefault(c => c.GetRuntimeName().Equals(colName));

                if (dillution != null)
                {
                    column.DataType.AlterTypeTo(dillution.Data_type);
                }

                if (drop)
                {
                    newTable.DropColumn(column);
                }
            }
        }
 public void AssignFieldsForProcessing(DiscoveredColumn field, List <DiscoveredColumn> fieldsToDiff, List <DiscoveredColumn> fieldsToUpdate)
 {
     //it is a hic internal field but not one of the overwritten, standard ones
     if (SpecialFieldNames.IsHicPrefixed(field)
         ||
         IsSupplementalMatch(field))
     {
         fieldsToUpdate.Add(field);
     }
     else
     {
         //it is not a hic internal field
         fieldsToDiff.Add(field);
         fieldsToUpdate.Add(field);
     }
 }
        public string BuildSelectListForAllColumnsExceptStandard(string tableAlias = "")
        {
            string sql = "";

            foreach (DiscoveredColumn col in _migrationColumnSet.FieldsToDiff)
            {
                //if it is hic_ or identity specification
                if (SpecialFieldNames.IsHicPrefixed(col) || col.IsAutoIncrement)
                {
                    continue;
                }

                sql += tableAlias + "[" + col.GetRuntimeName() + "],";
            }

            return(sql.TrimEnd(','));
        }
        protected void AssessMissingAndIgnoredColumns(DataTable chunk, IDataLoadEventListener job)
        {
            DiscoveredColumn[] listColumns = _dbInfo.ExpectTable(Table).DiscoverColumns();
            bool problemsWithColumnSets    = false;

            foreach (DataColumn colInSource in chunk.Columns)
            {
                if (!listColumns.Any(c => c.GetRuntimeName().Equals(colInSource.ColumnName, StringComparison.CurrentCultureIgnoreCase)))//there is something wicked this way coming, down the pipeline but not in the target table
                {
                    job.OnNotify(this, new NotifyEventArgs(ProgressEventType.Error,
                                                           "Column " + colInSource.ColumnName + " appears in pipeline but not destination table (" + Table + ") which is on (Database=" + _dbInfo.GetRuntimeName() + ",Server=" + _dbInfo.Server + ")"));

                    problemsWithColumnSets = true;
                }
            }
            foreach (DiscoveredColumn columnInDestination in listColumns)
            {
                if (columnInDestination.GetRuntimeName().Equals(SpecialFieldNames.DataLoadRunID) ||
                    columnInDestination.GetRuntimeName().Equals(SpecialFieldNames.ValidFrom))
                {
                    //its fine if validFrom/DataLoadRunID columns are missing
                    continue;//its fine
                }
                else
                if (!chunk.Columns.Contains(columnInDestination.GetRuntimeName()))    //its not fine if there are other columns missing (at the very least we should warn the user.
                {
                    bool isBigProblem = !SpecialFieldNames.IsHicPrefixed(columnInDestination);

                    job.OnNotify(this,
                                 new NotifyEventArgs(isBigProblem?ProgressEventType.Error:ProgressEventType.Warning, //hic_ columns could be ok if missing so only warning, otherwise go error
                                                     "Column " + columnInDestination.GetRuntimeName() + " appears in destination table (" + Table + ") but is not in the pipeline (will probably be left as NULL)"));

                    if (isBigProblem)
                    {
                        problemsWithColumnSets = true;
                    }
                }
            }

            if (problemsWithColumnSets)
            {
                throw new Exception("There was a mismatch between the columns in the pipeline and the destination table, check earlier progress messages for details on the missing columns");
            }
        }
Exemple #9
0
        private void CheckStagingToLiveMigrationForTable(DiscoveredTable stagingTable, DiscoveredColumn[] stagingCols, DiscoveredTable liveTable, DiscoveredColumn[] liveCols, ICheckNotifier notifier)
        {
            try
            {
                new MigrationColumnSet(stagingTable, liveTable, new StagingToLiveMigrationFieldProcessor()
                {
                    NoBackupTrigger = _loadMetadata.IgnoreTrigger
                });
                notifier.OnCheckPerformed(new CheckEventArgs("TableInfo " + liveTable + " passed " + typeof(MigrationColumnSet).Name + " check ", CheckResult.Success, null));
            }
            catch (Exception e)
            {
                notifier.OnCheckPerformed(new CheckEventArgs(
                                              typeof(MigrationColumnSet).Name + " reports a problem with the configuration of columns on STAGING/LIVE or in the ColumnInfos for TableInfo " + liveTable, CheckResult.Fail, e));
            }

            //live columns
            foreach (DiscoveredColumn col in liveCols)
            {
                if (!SpecialFieldNames.IsHicPrefixed(col) && col.IsAutoIncrement)                                                                                                        //must start hic_ if they are identities
                {
                    notifier.OnCheckPerformed(new CheckEventArgs("Column " + col + " is an identity column in the LIVE database but does not start with hic_", CheckResult.Fail, null)); //this one does not
                }
            }
            //staging columns
            foreach (DiscoveredColumn col in stagingCols) //staging columns
            {
                if (col.IsAutoIncrement)                  //if there are any auto increments
                {
                    notifier.OnCheckPerformed(new CheckEventArgs(
                                                  "Column " + col + " is an identity column and is in STAGING, the identity flag must be removed from the STAGING table", CheckResult.Fail, null));//complain since don't want a mismatch between IDs in staging and live or complaints about identity insert from SQL server
                }
            }
            //staging must allow null dataloadrunids and validfroms
            ConfirmNullability(stagingTable.DiscoverColumn(SpecialFieldNames.DataLoadRunID), true, notifier);
            ConfirmNullability(stagingTable.DiscoverColumn(SpecialFieldNames.ValidFrom), true, notifier);

            //live must allow nulls in validFrom
            ConfirmNullability(liveTable.DiscoverColumn(SpecialFieldNames.ValidFrom), true, notifier);
        }
Exemple #10
0
        /// <inheritdoc/>
        public IEnumerable <IHasStageSpecificRuntimeName> GetColumnsAtStage(LoadStage loadStage)
        {
            //if it is AdjustRaw then it will also have the pre load discarded columns
            if (loadStage <= LoadStage.AdjustRaw)
            {
                foreach (PreLoadDiscardedColumn discardedColumn in PreLoadDiscardedColumns.Where(c => c.Destination != DiscardedColumnDestination.Dilute))
                {
                    yield return(discardedColumn);
                }
            }

            //also add column infos
            foreach (ColumnInfo c in ColumnInfos)
            {
                if (loadStage <= LoadStage.AdjustRaw && SpecialFieldNames.IsHicPrefixed(c))
                {
                    continue;
                }
                else
                if (loadStage <= LoadStage.AdjustStaging && c.IsAutoIncrement) //auto increment columns do not get created in RAW/STAGING
                {
                    continue;
                }
                else
                if (loadStage == LoadStage.AdjustStaging &&
                    //these two do not appear in staging
                    (c.GetRuntimeName().Equals(SpecialFieldNames.DataLoadRunID) || c.GetRuntimeName().Equals(SpecialFieldNames.ValidFrom))
                    )
                {
                    continue;
                }
                else
                {
                    yield return(c);
                }
            }
        }
        private void RefreshUIFromDatabase()
        {
            lbPrimaryKeys.Items.Clear();
            lbConflictResolutionColumns.Items.Clear();

            foreach (var pkCol in _table.ColumnInfos.Where(col => col.IsPrimaryKey))
            {
                //primary keys are not used to resolve duplication of primary key values (obviously!)
                if (pkCol.DuplicateRecordResolutionOrder != null)
                {
                    //unset any that have accidentally gained an order e.g. if user set an order then made a new column a PK
                    pkCol.DuplicateRecordResolutionOrder = null;
                    pkCol.SaveToDatabase();
                }


                lbPrimaryKeys.Items.Add(pkCol);
            }

            List <IResolveDuplication> resolvers = new List <IResolveDuplication>();

            resolvers.AddRange(_table.ColumnInfos.Where(col => !col.IsPrimaryKey));
            resolvers.AddRange(_table.PreLoadDiscardedColumns);

            //if there is no order yet
            if (resolvers.All(r => r.DuplicateRecordResolutionOrder == null))
            {
                for (int i = 0; i < resolvers.Count; i++)
                {
                    //set one up
                    resolvers[i].DuplicateRecordResolutionOrder = i;
                    resolvers[i].SaveToDatabase();
                }
            }


            foreach (IResolveDuplication resolver in resolvers.OrderBy(o => o.DuplicateRecordResolutionOrder).ToArray())
            {
                //if it starts with hic_
                if (SpecialFieldNames.IsHicPrefixed(resolver))
                {
                    //do not use it for duplication resolution
                    resolver.DuplicateRecordResolutionOrder       = null;
                    resolver.DuplicateRecordResolutionIsAscending = false; //default to descending
                    resolver.SaveToDatabase();
                    resolvers.Remove(resolver);
                }
            }

            foreach (IResolveDuplication resolver in resolvers.OrderBy(c => c.DuplicateRecordResolutionOrder))
            {
                lbConflictResolutionColumns.Items.Add(resolver);
            }

            QueryEditor.ReadOnly = false;

            try
            {
                //this is used only to generate the SQL preview of how to resolve primary key collisions so no username/password is required - hence the null,null
                PrimaryKeyCollisionResolver resolver = new PrimaryKeyCollisionResolver(_table);
                QueryEditor.Text = resolver.GenerateSQL();
                CommonFunctionality.ScintillaGoRed(QueryEditor, false);
            }
            catch (Exception e)
            {
                CommonFunctionality.ScintillaGoRed(QueryEditor, e);
            }

            QueryEditor.ReadOnly = true;
        }
        public void CloneTable(DiscoveredDatabase srcDatabaseInfo, DiscoveredDatabase destDatabaseInfo, DiscoveredTable sourceTable, string destTableName, bool dropHICColumns, bool dropIdentityColumns, bool allowNulls, PreLoadDiscardedColumn[] dilutionColumns)
        {
            if (!sourceTable.Exists())
            {
                throw new Exception("Table " + sourceTable + " does not exist on " + srcDatabaseInfo);
            }


            //new table will start with the same name as the as the old scripted one
            DiscoveredTable newTable = destDatabaseInfo.ExpectTable(destTableName);

            var sql = sourceTable.ScriptTableCreation(allowNulls, allowNulls, false /*False because we want to drop these columns entirely not just flip to int*/, newTable);

            _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, "Creating table with SQL:" + sql));

            using (var con = destDatabaseInfo.Server.GetConnection())
            {
                con.Open();
                using (var cmd = destDatabaseInfo.Server.GetCommand(sql, con))
                    cmd.ExecuteNonQuery();
            }

            if (!newTable.Exists())
            {
                throw new Exception("Table '" + newTable + "' not found in " + destDatabaseInfo + " despite running table creation SQL!");
            }

            foreach (DiscoveredColumn column in newTable.DiscoverColumns())
            {
                bool drop    = false;
                var  colName = column.GetRuntimeName();

                if (column.IsAutoIncrement)
                {
                    drop = true;
                }

                //drop hic_ columns
                if (SpecialFieldNames.IsHicPrefixed(colName) && dropHICColumns)
                {
                    drop = true;
                }

                //if the ColumnInfo is explicitly marked to be ignored
                if (_tableInfo.ColumnInfos.Any(c => c.IgnoreInLoads && c.GetRuntimeName(_copyToBubble.ToLoadStage()).Equals(colName)))
                {
                    _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"{colName} will be dropped because it is marked IgnoreInLoads"));
                    drop = true;
                }


                //also drop any columns we have specifically been told to ignore in the DLE configuration
                if (_hicDatabaseConfiguration.IgnoreColumns != null && _hicDatabaseConfiguration.IgnoreColumns.IsMatch(colName))
                {
                    _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"{colName} will be dropped because it is matches the gloabl ignores pattern ({_hicDatabaseConfiguration.IgnoreColumns})"));
                    drop = true;
                }

                //drop the data load run ID field and validFrom fields, we don't need them in STAGING or RAW, it will be hard coded in the MERGE migration with a fixed value anyway.
                if (colName.Equals(SpecialFieldNames.DataLoadRunID) || colName.Equals(SpecialFieldNames.ValidFrom))
                {
                    drop = true;
                }

                var dilution = dilutionColumns.SingleOrDefault(c => c.GetRuntimeName().Equals(colName));

                if (dilution != null)
                {
                    _listener.OnNotify(this, new NotifyEventArgs(ProgressEventType.Information, $"Altering diluted column {colName} to {dilution.Data_type}"));
                    column.DataType.AlterTypeTo(dilution.Data_type);
                }

                if (drop)
                {
                    newTable.DropColumn(column);
                }
            }
        }