/*============================================================================= 

Propose data classification to all columns in database


Creation : 29.03.2023 / TSC
Modifications:

=============================================================================*/ 
SET XACT_ABORT ON;
SET NOCOUNT ON;

USE [ActivePos_read]
GO

IF OBJECT_ID('dbo.setSensitivity') IS NOT NULL 
BEGIN 
    DROP PROCEDURE dbo.setSensitivity;
END
GO

CREATE PROCEDURE dbo.setSensitivity
    @schemaName VARCHAR(100)
    ,@tableName VARCHAR(100)
    ,@columnName VARCHAR(100)
    ,@category VARCHAR(100)
    ,@sensitivity VARCHAR(100)
    ,@rank VARCHAR(10) = 'LOW'
    ,@removeClassification BIT = 0

AS 
BEGIN   
    DECLARE @useSql2019Syntax BIT = 0;
    DECLARE @command NVARCHAR(MAX)='';
    SELECT @useSql2019Syntax = CASE
        WHEN CAST(SERVERPROPERTY('productversion')  AS VARCHAR(2)) >= 15 THEN 1
        ELSE 0
    END 
    SET @rank = UPPER(@rank);
    
    --PRINT '
    --@schemaName             : '+ISNULL(CONVERT(VARCHAR(200),@schemaName),'NULL')+'
    --@tableName              : '+ISNULL(CONVERT(VARCHAR(200),@tableName),'NULL')+'
    --@columnName             : '+ISNULL(CONVERT(VARCHAR(200),@columnName),'NULL')+'
    --@category               : '+ISNULL(CONVERT(VARCHAR(200),@category),'NULL')+'
    --@sensitivity            : '+ISNULL(CONVERT(VARCHAR(200),@sensitivity),'NULL')+'
    --@rank                   : '+ISNULL(CONVERT(VARCHAR(200),@rank),'NULL')+'
    --@removeClassification   : '+ISNULL(CONVERT(VARCHAR(200),@removeClassification),'NULL')+'
    --'

    IF @useSql2019Syntax = 0
    BEGIN
        --PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - using pre-sql 2019 syntax';
        
        IF EXISTS (
            SELECT NULL 
            FROM SYS.EXTENDED_PROPERTIES 
            WHERE [major_id] = OBJECT_ID(@schemaName+'.'+@tableName) AND [name] = N'sys_information_type_name' 
            AND [minor_id] = (
                SELECT [column_id] 
                FROM SYS.COLUMNS 
                WHERE [name] = @columnName 
                AND [object_id] = OBJECT_ID(@schemaName+'.'+@tableName)
            )
        )
        EXECUTE [sys].[sp_dropextendedproperty]
            @name = N'sys_information_type_name', 
            @level0type = N'SCHEMA', @level0name = @schemaName, 
            @level1type = N'TABLE', @level1name = @tableName, 
            @level2type = N'COLUMN', @level2name = @columnName;
        ;

        IF EXISTS (
            SELECT NULL 
            FROM SYS.EXTENDED_PROPERTIES 
            WHERE [major_id] = OBJECT_ID(@schemaName+'.'+@tableName) AND [name] = N'sys_sensitivity_label_name' 
            AND [minor_id] = (
                SELECT [column_id] 
                FROM SYS.COLUMNS 
                WHERE [name] = @columnName 
                AND [object_id] = OBJECT_ID(@schemaName+'.'+@tableName)
            )
        )
        EXECUTE [sys].[sp_dropextendedproperty]
            @name = N'sys_sensitivity_label_name', 
            @level0type = N'SCHEMA', @level0name = @schemaName, 
            @level1type = N'TABLE', @level1name = @tableName, 
            @level2type = N'COLUMN', @level2name = @columnName;
        ;

        IF @removeClassification = 0
        BEGIN 
            EXEC [sys].[sp_addextendedproperty]
            @name = N'sys_information_type_name', @value = @category,  
            @level0type = N'Schema', @level0name = @schemaName,  
            @level1type = N'Table', @level1name = @tableName,   
            @level2type = N'Column',@level2name = @columnName;  

            EXEC [sys].[sp_addextendedproperty]
            @name = N'sys_sensitivity_label_name', @value = @sensitivity,  
            @level0type = N'Schema', @level0name = @schemaName,  
            @level1type = N'Table', @level1name = @tableName,   
            @level2type = N'Column',@level2name = @columnName;  
        END 
    END 
    ELSE
    BEGIN
        PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - using sql 2019 syntax';

        IF @removeClassification = 0
        BEGIN 
            SET @command ='ADD SENSITIVITY CLASSIFICATION TO ['+@schemaName+'].['+@tableName+'].['+@columnName+'] WITH ( LABEL='''+@sensitivity+''', INFORMATION_TYPE='''+@category+''', RANK='+@rank+' );'
            PRINT @command;
            EXEC(@command);
        END 
        ELSE 
        BEGIN
            SET @command = 'DROP SENSITIVITY CLASSIFICATION FROM ['+@schemaName+'].['+@tableName+'].['+@columnName+'];'
            PRINT @command;
            EXEC(@command);
        END 
    END
END 
GO

--#region vars
DECLARE @Tblpattern TABLE(
    patternId INT IDENTITY NOT NULL 
    ,pattern VARCHAR(100) NOT NULL 
    ,toExclude BIT NOT NULL DEFAULT 0
);

IF OBJECT_ID('tempdb..#classification')IS NOT NULL BEGIN;
    DROP TABLE #classification;
END;

CREATE TABLE #classification (
    [table_schema] sysname NOT NULL 
    ,[table_name] sysname NOT NULL 
    ,[column_name] sysname NOT NULL 
    ,[data_type] sysname NOT NULL
    ,[matchedByPattern] VARCHAR(100) NOT NULL 
    ,[matchedInsideField] BIT NOT NULL DEFAULT 0
);

IF OBJECT_ID('tempdb..#all_text_fields')IS NOT NULL BEGIN;
    DROP TABLE #all_text_fields;
END;

CREATE TABLE #all_text_fields (
    [table_schema] VARCHAR(255) NOT NULL 
    ,[table_name] VARCHAR(255) NOT NULL 
    ,[column_name] VARCHAR(255) NOT NULL 
    ,[data_type] VARCHAR(255) NOT NULL
    ,[matchedByPattern] VARCHAR(100) NULL 
);

IF OBJECT_ID('tempdb..#existing_classification')IS NOT NULL BEGIN;
	DROP TABLE #existing_classification;
END;

CREATE TABLE #existing_classification(
    [table_schema] VARCHAR(255) NOT NULL 
    ,[table_name] VARCHAR(255) NOT NULL 
    ,[column_name] VARCHAR(255) NOT NULL 
    ,[category] VARCHAR(255)
    ,[sensibility] VARCHAR(100)
    ,[rank] VARCHAR(20)
);

DECLARE @pattern VARCHAR(100);
DECLARE @toExclude BIT = 0;
DECLARE @cmd VARCHAR(MAX)='';
DECLARE @schema_name VARCHAR(100);
DECLARE @table_name VARCHAR(100);
DECLARE @column_name VARCHAR(100);
DECLARE @data_type VARCHAR(100);
DECLARE @searchInFields BIT = 1;
DECLARE @assignUnmatchedColumns BIT = 1;
DECLARE @useSql2019Syntax BIT = CASE
    WHEN CAST(SERVERPROPERTY('productversion')  AS VARCHAR(2)) >= 15 THEN 1
    ELSE 0
END ;
DECLARE @tplCheckInField VARCHAR(MAX)='
INSERT INTO #classification(
    [table_schema]
    ,[table_name]
    ,[column_name]
    ,[matchedByPattern]
    ,[data_type]
    ,[matchedInsideField]
)
SELECT DISTINCT
    ''@schema@''
    ,''@tbl@''
    ,''@field@''
    ,''@pattern@''
    ,''@data_type@''
    ,1
FROM [@schema@].[@tbl@] x
WHERE x.[@field@] like ''@pattern@''
AND NOT EXISTS(
    SELECT 1
    FROM #classification c
    WHERE c.[table_schema] = ''@schema@''
    AND c.[table_name] = ''@tbl@''
    AND c.[column_name] = ''@field@''
);
';
--#endregion

/* 
If true, search inside text fields longer than 90 characters for occurence of the defined patterns 
Only non computed columns of tables are checked (views are ignored, computed columns are ignored)
If false, the search inside the fields is skipped.
*/
SET @searchInFields = 0;

/* 
if true, every columns that is not matched by a pattern will be marked as category: Other, sensitivity: General 
if false, no classification will be set on the column. Existing classification will be removed.
*/
SET @assignUnmatchedColumns = 01;

--#region populate patterns
INSERT INTO @Tblpattern ([pattern])
VALUES('%last%name%')
,('%first%name%')
,('%surname%')
,('%maiden%name%')
,('%full%name%')
,('%family%name%')
,('%birthday%')
,('%date%of%birth%')
,('%birth%date%')
,('dob')
,('%email%')
,('%e-mail%')
,('%addr%')
,('%street%')
,('%city%')
,('%phone%')
,('%mobile%')
,('%natel%')
,('%area%code%')
,('%postal%')
,('%zip%')
,('%npa%')
,('%AVS%')
,('%AHV%')
,('%social_security_number%')
,('%fidelity%')
,('%loyalty_card%')
,('%insurance_card%')
,('%vip_card%')
,('%starcard%')
,('%covercard%')

INSERT INTO @Tblpattern ([pattern],
                         [toExclude])
VALUES('%periodicity%', 1)
--,('%text', 1)
,('%id', 1)
--#endregion

--#region find all fields that match the patterns
DECLARE crsPatternInclude CURSOR FAST_FORWARD READ_ONLY FOR 
    SELECT [pattern], [toExclude]
    FROM @Tblpattern c
    WHERE c.[toExclude] = 0

OPEN crsPatternInclude

FETCH NEXT FROM crsPatternInclude INTO @pattern, @toExclude

WHILE @@FETCH_STATUS = 0
BEGIN
    
    INSERT INTO [#classification] ([table_schema],
                                   [table_name],
                                   [column_name],
                                   [matchedByPattern]
                                   ,[data_type])
    SELECT [c].[TABLE_SCHEMA], [c].[TABLE_NAME], [c].[COLUMN_NAME], @pattern, c.[DATA_TYPE]
     FROM [INFORMATION_SCHEMA].[COLUMNS] c
     WHERE c.[COLUMN_NAME] LIKE @pattern
     AND EXISTS(
        /* is in a table and not a view */
        SELECT 1
        FROM sys.[tables] st
        WHERE SCHEMA_NAME(st.[schema_id]) = c.[TABLE_SCHEMA]
        AND st.[name] = c.[TABLE_NAME]
        AND st.[type_desc] = 'USER_TABLE'
     )
     AND NOT EXISTS (
        /* column is not already in the list */
        SELECT 1
        FROM [#classification] t
        WHERE t.[table_schema] = c.[TABLE_SCHEMA] 
        AND t.[table_name] = c.[TABLE_NAME]
        AND t.[column_name] = c.[COLUMN_NAME]
     )
     AND NOT EXISTS (
        /* not a PK */
        SELECT            1
          FROM            sys.tables tab
          LEFT OUTER JOIN sys.indexes pk
            ON tab.object_id = pk.object_id
           AND [pk].[is_primary_key] = 1
         OUTER APPLY      (   
            SELECT      [col].[name]
            FROM      sys.index_columns ic
            INNER JOIN sys.columns col
                ON ic.object_id = col.object_id
                AND ic.column_id = col.column_id
            WHERE      ic.object_id = tab.object_id
                AND      [ic].[index_id]   = pk.index_id
        ) D(column_names)
         WHERE            [D].[column_names] IS NOT NULL
         AND d.[column_names] = c.[COLUMN_NAME]
         AND tab.[name] = c.[TABLE_NAME]
         AND SCHEMA_NAME(tab.[schema_id]) = c.[TABLE_SCHEMA]
     )
     AND NOT EXISTS(
        /* not a FK */
        SELECT 1
        FROM sys.foreign_key_columns AS fkc
            INNER JOIN sys.foreign_keys AS fk ON fkc.constraint_object_id = fk.object_id
            INNER JOIN sys.tables AS t ON fkc.parent_object_id = t.object_id
            INNER JOIN sys.tables AS rt ON fkc.referenced_object_id = rt.object_id
            INNER JOIN sys.columns AS pc ON fkc.parent_object_id = pc.object_id
               AND fkc.parent_column_id = pc.column_id
            INNER JOIN sys.columns AS c1 ON fkc.referenced_object_id = c1.object_id
               AND fkc.referenced_column_id = c1.column_id
        WHERE SCHEMA_NAME(t.[schema_id]) = c.[TABLE_SCHEMA]
        AND t.[name] = c.[TABLE_NAME]
        AND pc.[name] = c.[COLUMN_NAME]
     )
     /* only consider columns holding number, text and xml. */
     AND c.[DATA_TYPE] IN (
        'text',
        'ntext',
        'varchar',
        'char',
        'nvarchar',
        'nchar',
        'sysname',
        'Account_numbers',
        'Alpha_table_key',
        'Large_name_field',
        'Medium_remarks',
        'Normal_name_field',
        'Small_alphabetical_field',
        'Small_remarks',
        'Userid',
        'Week',
        'VGUID_identifier',
        'Large_text',
        'Large_remarks',
        'tinyint',
        'smallint',
        'int',
        'real',
        'money',
        'float',
        'decimal',
        'numeric',
        'bigint',
        'xml',
        'Small_integer'
     )
     AND NOT EXISTS(
        /* ignore computed columns */
        SELECT 1
        FROM sys.[tables] t
            JOIN sys.columns c1 ON c1.[object_id] = t.[object_id]
        WHERE c1.[is_computed] = 1
        AND SCHEMA_NAME(t.[schema_id]) = c.[TABLE_SCHEMA]
        AND t.[name] = c.[TABLE_NAME]
        AND c1.[name] = c.[COLUMN_NAME]
    )
     /* do not process known tables not used anymore. see OCTP-724 */
     AND c.[TABLE_SCHEMA]+'.'+c.[TABLE_NAME] NOT IN(
        'dbo.TT_File_Transfer',
        'dbo.pfs_gdi$',
        'dbo.BOM_revision',
        'dbo.fixed_price_Pmed_bkp',
        'dbo.Project_weighting',
        'dbo.TT_Visilab_AD_AMR_regular_import',
        'dbo.ATS_time_period_balance',
        'dbo.EMCH_payroll_period_link',
        'dbo.TT_LD_EMC_Payroll_Var',
        'dbo.TT_Visilab_address_data_regular_import',
        'dbo.WKPA_capacity',
        'dbo.Clocking_summary',
        'dbo.APS_version_hist_detail',
        'dbo.TT_Synchro_Account_List',
        'dbo.EAS_APS_operation_link',
        'dbo.EMC_absence',
        'dbo.TT_Payroll_Stat',
        'dbo.Manual_clocking',
        'dbo.TT_Visilab_IT_AMR_regular_import',
        'dbo.Activity_supplement',
        'dbo.ZDBA_localisation',
        'dbo.Clocking',
        'dbo.TT_Visilab_item_data_regular_import',
        'dbo.TT_Galenicare_Bonart',
        'dbo.Process_revision',
        'dbo.PCA_EMC_absence',
        'dbo.TT_Search_Item',
        'dbo.TT_Pre_Calc',
        'wkl.ArizonaToWKLDataTransformationLog',
        'dbo.Sheet1$',
        'dbo.EMC_termination_type',
        'dbo.Family_allowance',
        'dbo.TT_EPP_Withholding_Tax',
        'dbo.EMC_termination_reason',
        'dbo.TT_GetNext_ID',
        'dbo.TT_LORE_item_facing',
        'dbo.Interco_synchronization',
        'dbo.TT_Tax_List_Recap',
        'dbo.Quantity_formula_detail',
        'dbo.TT_VMI',
        'dbo.Payroll_batch_bank',
        'dbo.TT_LD_generic_item',
        'dbo.Occupation',
        'dbo.Pro_svc_received_answer',
        'dbo.TT_DL_planning',
        'dbo.Asset_insurance',
        'dbo.TT_Visilab_ADG_AMR_regular_import',
        'dbo.Payroll_batch_detail',
        'dbo.TT_PH_RG_Label_Print',
        'dbo.Asset_leasing',
        'dbo.TT_Visilab_data_regular_import',
        'dbo.EAS_structure_operation',
        'dbo.Time_table_schema_history',
        'dbo.TT_PH_purchase_order_error',
        'dbo.PDX_mapping_wholesaler',
        'dbo.Event_premise',
        'dbo.TT_DH_Manual_Stock_Allocation',
        'dbo.TT_Clocking_Key_Status',
        'dbo.Asset_maintenance',
        'dbo.TT_STM',
        'dbo.Symptom',
        'dbo.External_entry',
        'dbo.PRH_list_column_link',
        'dbo.TTSNH_authorized_status',
        'dbo.TT_User_Badge_Identifier',
        'dbo.ATT_time_period_balance',
        'dbo.EAS_structure_trigger',
        'dbo.TT_SN_DH_WKO',
        'dbo.TT_GAL_Price_Factor',
        'dbo.Contract_daily_time',
        'dbo.TT_LD_Doc_Line',
        'dbo.TT_DL_Part_List_Exchange',
        'dbo.HR_certificate',
        'dbo.TT_Synchro',
        'dbo.TT_WKOP',
        'dbo.TT_BRE_Plan_Fab_Index',
        'dbo.TT_IMP_bom_item',
        'dbo.Time_table_type_history',
        'dbo.Contract_time_adjustment',
        'dbo.TT_LD_EMC_periodicity',
        'dbo.TT_IMP_item',
        'dbo.Time_table_type_detail',
        'dbo.Facility_technical_criteria',
        'dbo.TT_LD_PR_Employee_Profile',
        'dbo.TT_IMP_item_2',
        'dbo.TT_IMP_item_stock',
        'dbo.PR_certificate_header',
        'dbo.TT_PRCH',
        'dbo.TT_IMP_item_cover_date',
        'dbo.TT_LD_IT_Category_management',
        'dbo.TT_IMP_item_conso',
        'dbo.PRH_activity_type_link',
        'dbo.Payroll_scale_date',
        'dbo.TT_OU_Price_Code_Priority',
        'dbo.TT_IMP_item_PL',
        'dbo.OFFCLD_reject',
        'dbo.TT_LD_DH_FINA',
        'dbo.TT_IMP_item_PL_Tot',
        'upd.Change_tracking_monitor',
        'dbo.TT_PH_APOS_item_status',
        'dbo.Payroll_calc_detail',
        'dbo.TT_DH_auto_addr',
        'dbo.TT_IMP_wko',
        'dbo.FA_RAFAM_type',
        'dbo.Alloy_element_quantity',
        'dbo.Arrondis$',
        'dbo.Alloy_element',
        'dbo.TT_IMP_DL',
        'dbo.Prescription_task_link',
        'dbo.WKOP_planning_header',
        'dbo.TT_DH_auto_document_line',
        'dbo.Alloy_detail',
        'dbo.TT_IMP_DL_1',
        'dbo.TT_PHGD_Fixed_Price',
        'dbo.TT_IMP_Matr',
        'dbo.PRH_layout_link',
        'dbo.TT_PHGD_Exp_AC',
        'dbo.PerformancePoint',
        'dbo.Offline_clocking',
        'dbo.PerformancePointAggregation',
        'dbo.TT_PHGD_Exp_ACBARCODE',
        'dbo.ATT_cust_list_column',
        'dbo.HR_training_field',
        'dbo.TT_BCR_WKO',
        'dbo.Weekly_schema_detail',
        'dbo.PRH_period_type',
        'dbo.sysdiagrams',
        'dbo.TT_PHGD_Exp_ACNAM',
        'dbo.TT_Auto_Data_Acquisition',
        'dbo.PRH_totalizator_link',
        'dbo.RAFAM_action_monitor',
        'dbo.Knowledge_category',
        'dbo.ATT_list_column_link',
        'dbo.Knowledge_base_category',
        'dbo.TT_BCR_RECAP_T2',
        'wkl.ServiceBrokerError',
        'dbo.TT_PHGD_Exp_NETART_ACTION',
        'dbo.HR_training_type',
        'dbo.TT_LD_budget',
        'dbo.TT_Export_WHSPRICE',
        'dbo.PJS_totalizator_link',
        'dbo.Knowledge_base_key',
        'dbo.PR_cust_list_column',
        'dbo.TT_PHGD_Exp_NETART_GREEN',
        'dbo.Bmc_license',
        'del.PH_qualification',
        'dbo.TT_PHGD_Exp_WHSPRICE',
        'dbo.BMH_rule_type_link',
        'dbo.TT_Ctrl_Item_PH',
        'dbo.TT_LD_Fixed_Price_Factor',
        'dbo.PCA_EMC_loan',
        'dbo.TT_Export_NETART_GREEN',
        'dbo.Process_document',
        'dbo.EFT_OW_rule',
        'dam.MonitorTableHash',
        'dbo.BOM_rule',
        'dbo.TT_Export_NETART_ACTION',
        'dbo.ACS_totalizator_link',
        'dbo.BML_rule_link',
        'dbo.TT_Export_ACNAM',
        'dbo.PR_global_value_link',
        'dam.HashValueUniqueIndexInt',
        'dbo.CCI_address_key',
        'dbo.Contract_time_table_header',
        'dbo.TT_DWH_sales_extraction',
        'dbo.Custom_export_licence',
        'dbo.BMOH_selected_rule',
        'dbo.dtproperties',
        'dbo.TT_SUN_Web_Item',
        'dam.HashValueUniqueIndexGuid',
        'dbo.TT_LD_Item_Visilab',
        'dbo.TT_DWH_price_modifier_extraction',
        'dbo.Payroll_period_type',
        'dbo.TT_AC_ACPE_lock',
        'dbo.Bmc_system',
        'dbo.Process_document_link',
        'dbo.TT_ITQ_Export',
        'dbo.TT_Export_AC',
        'dbo.Surplus_line',
        'dbo.Process_line_antecedence',
        'dbo.Project_resource',
        'dbo.TT_PH_ITQ_Import',
        'dbo.PRCH_EPP_link',
        'dbo.TT_INB_generation',
        'dbo.systranschemas',
        'dbo.Process_line_option',
        'dbo.PJS_layout_detail',
        'dbo.TT_OU_advertising_process',
        'dbo.TT_LD_CCI_ATA_online',
        'dbo.Process_overlap_line',
        'dbo.Clocking_message',
        'dbo.TT_DH_transitory',
        'dbo.GaldatItemsWithStatus',
        'dbo.CLK_user_interface',
        'dbo.BMOH_formula_variable',
        'dbo.PJS_task_selection',
        'dbo.TT_Web_Item',
        'dbo.TT_Ctrl_Item',
        'dbo.Item_alloy_quantity',
        'dbo.CLT_authorized_CLKG',
        'dbo.Machine_downtime',
        'dbo.Element_transaction',
        'dbo.Task_resource',
        'dbo.EMC_certificate_layout',
        'dbo.AUTO_to_round$',
        'dbo.TT_CICR_LD_PCEM',
        'dbo.BOM_location',
        'dbo.Payroll_period',
        'dbo.Clocking_terminal_profile',
        'dbo.TT_ITSH_generation',
        'dbo.TT_PHFCM_extraction',
        'dbo.PRH_PRHC_link',
        'dbo.Offline_clocking_detail',
        'dbo.CLTP_schedule',
        'dbo.TT_IT',
        'dbo.HR_skill_level',
        'dbo.AX_item_mappings_rules',
        'dbo.CLTP_user_interface',
        'dbo.PHGD_MCMTXT_TEMP',
        'dbo.TT_ITCAT',
        'dbo.TT_FUN_OUSH_link',
        'dbo.Task_budget_detail',
        'dbo.Asset_investment_history',
        'dbo.HR_skill_type',
        'dbo.TT_OU_store_history',
        'dbo.Salary_grade_funct_link',
        'dbo.WKOP_planning',
        'dbo.Process_overlap_header',
        'dbo.Event_sector',
        'dbo.zz_tr_01',
        'dbo.TT_address_exp',
        'dbo.document_line_link_pda',
        'dbo.TT_address_exp_ESC',
        'dbo.TT_address_double',
        'dbo.TT_PMP',
        'dbo.Wprice_item',
        'dbo.TT_item_PV',
        'dbo.TriaFact_AutoCorrect',
        'dbo.TT_fobl_lines',
        'dbo.PHGD_FCMTXT_lpe',
        'dbo.PHGD_MCMTXT_lpe',
        'dbo.TT_item_availability_check_mouchard',
        'dbo.patient_card_fid$',
        'dbo.temp_mouchard_stm',
        'dbo.T_STM_Create',
        'dbo.TT_Change_tracking_history',
        'dbo.TT_change_tracking_triggers',
        'del.Address_merge_prevalidation',
        'del.PDX_mapping_wholesaler',
        'dbo.Bmc_application_default_backup_vesta',
        'dbo.ITCAT_IT_link_09_09_2015',
        'dbo.Config_Sync_V',
        'dbo.TT_PPUB_itk_src',
        'dbo.preissenkung',
        'dbo.tt_compteur',
        'dbo.DBA_Label_Monitoring',
        'dbo.DBA_Servers_Site',
        'dbo.LORE_supplying_procedure_savGBA',
        'dbo.brand$',
        'dbo.brand_line$',
        'dbo.TT_PPUB_itk',
        'dbo.brl_phcode$',
        'dbo.TT_xPUB_itk',
        'dbo.tt_GBA_list',
        'dbo.TT_Criteria',
        'dbo.DBA_Job_Monitoring',
        'dbo.TT_item_II',
        'dbo.DBA_Job_List',
        'dbo.TT_item_type_2',
        'dbo.TT_item_type_3',
        'dbo.TT_item_type_5',
        'dbo.TT_item_type_6',
        'dbo.Item_LORE_min_max_614',
        'dbo.Bichsel',
        'dbo.TT_Item_20171005',
        'dbo.xpub_to_upload',
        'dbo.TT_OU_price_code_priority_20171026',
        'dbo.RAFAM_notification_error',
        'dbo.aps_monitor_table_SUN_SPE',
        'dbo.TT_GBA_Supplier',
        'dbo.aps_monitor_table_SUN_SPE2',
        'dbo.temp_PHGD_ACCHAIN',
        'dbo.TT_address',
        'dbo.S13X_NUS',
        'dbo.TT_itsh',
        'dbo.sales_tax_code_sav',
        'dbo.tt_err_sync_dve',
        'dbo.sales_tax_rate_sav',
        'dbo.SAV_bmc_user_role',
        'dbo.TT_maj_default_supplier',
        'dbo.TT_item',
        'dbo.TT_Fusion_Item_relation_info',
        'dbo.SUN_DBA_LOGS',
        'dbo.LD_external_item',
        'dbo.item_link_del',
        'dbo.KuKo038',
        'dbo.LORE_item_facing_20160302',
        'dbo.tt_table',
        'dbo.MinMax_Facings_Output$',
        'dbo.vip_card_20040831',
        'dbo.TT_records',
        'dbo.Account_link_secu_doublon',
        'dbo.Account_chart_secu_doublon',
        'dbo.Account_secu_doublon',
        'dbo.Account_key_secu_doublon',
        'dbo.Account_text_secu_doublon',
        'dbo.Account_chart_secu_doublons_SPE',
        'dbo.TT_Upd_Account',
        'dbo.item_quantity_sav_20170405',
        'dbo.Account_chart_secu_doublons',
        'dbo.date_peremption$',
        'dbo.Address_group_text_Merge',
        'dbo.Bmc_user_role_2016_04_04',
        'dbo.TT_fusion_Item_status_history_II',
        'dbo.TT_Sync_Autoprod_AZ',
        'dam.ChecksumUniqueIndex_Work_type_text',
        'dbo.LD_item_FP',
        'dbo.Entry_Debug',
        'dbo.TT_excepted_field',
        'dbo.LORE_item_Facing20160308',
        'dbo.tt_ld_entry_dpa',
        'dbo.t_adk',
        'dbo.FUN_OUSH_link_patrice',
        'dbo.tt_ld_entry_dpa_2',
        'dbo.Entry_Sans_DH',
        'dbo.TT_PHGD_AC_Ins_Code',
        'dbo.TT_Rayons_textes',
        'dbo.TT_OU_advertising_process_dca',
        'dbo.OU_store_type_2016_05_12',
        'dbo.OU_store_type_text_2016_05_12',
        'dbo.ACS_totalizator_link_dve',
        'dbo.TT_XPUB_itk',
        'dbo.tt_gal_price_factor',
        'dbo.pda_CRM_reprocessing',
        'dbo.TT_Address',
        'dbo.Item_LORE_min_max_complet',
        'dbo.TT_Fusion_Item',
        'dbo.ZZ_DVE_SYNC',
        'dbo.Item_catalog_text_2016_11_09',
        'dbo.TT_fusion_Address',
        'dbo.ITCAT_IT_link_2016_11_09',
        'dbo.TT_Fusion_Item_text',
        'dbo.TT_Fusion_Item_sale',
        'dbo.TT_Fusion_PH_Item',
        'dbo.TT_fusion_telecom',
        'dbo.TT_ITSH',
        'dbo.TT_Fusion_Item_Status_History',
        'dbo.TT_LORE_item_facing_20150609',
        'dbo.TT_SUN_sp_exported',
        'dbo.LORE_service_level_rate_2016_08_19',
        'dbo.z_dve_pharmacode',
        'dbo.OU_store_history_2016_08_22',
        'dbo.DPA_tax_list',
        'dbo.DPA_dh_tax',
        'dbo.Item_statistics_yearly_OLD',
        'dbo.TT_fusion_item_relation_info',
        'dbo.APS_monitor_row_OLD',
        'dbo.APS_monitor_row_OLD2',
        'dbo.Item_statistics_monthly_new',
        'dbo.Item_statistics_yearly_new',
        'dbo.ph_item_20040325',
        'dbo.t_ol',
        'dbo.t_ol2',
        'dbo.zz_dve_duree',
        'dbo.MSmerge_tombstone',
        'dbo.MSmerge_contents',
        'dbo.MSmerge_genhistory',
        'dbo.MSmerge_settingshistory',
        'dbo.sysmergeschemachange',
        'dbo.sysmergesubsetfilters',
        'dbo.MSdynamicsnapshotjobs',
        'dbo.MSmerge_altsyncpartners',
        'dbo.MSmerge_partition_groups',
        'dbo.MSmerge_generation_partition_mappings',
        'dbo.MSmerge_current_partition_mappings',
        'dbo.MSmerge_past_partition_mappings',
        'dbo.MSmerge_dynamic_snapshots',
        'dbo.MSmerge_supportability_settings',
        'dbo.MSmerge_sessions',
        'dbo.MSmerge_log_files',
        'dbo.MSmerge_articlehistory',
        'dbo.MSrepl_errors',
        'dbo.MSmerge_history',
        'dbo.MSmerge_agent_parameters',
        'dbo.MSmerge_conflicts_info',
        'dbo.MSmerge_metadataaction_request',
        'dbo.MSmerge_errorlineage',
        'dbo.tmpOrdonnance',
        'dbo.MSmerge_identity_range',
        'dbo.sysmergepartitioninfo',
        'vesta.VestaVersion',
        'del.PHGD_WHS',
        'del.PHGD_WHSPRICE',
        'del.PHGD_AC',
        'del.PHGD_ACACT',
        'del.PHGD_ACBARCODE',
        'del.PHGD_ACCHAIN',
        'del.PHGD_ACCOMP',
        'del.PHGD_ACLIM',
        'del.PHGD_ACNAM',
        'del.PHGD_ACPRICEALG',
        'del.PHGD_ACMED',
        'del.Numerary_value',
        'del.PHGD_ACWHS',
        'del.Numerary_value_text',
        'del.PHGD_COMP',
        'dbo.ZZ_DVE_Item_calc_besoin',
        'dbo.TT_MESA_narcotic_export',
        'dbo.Item_LORE_min_max_test',
        'dbo.pda_duration_1500_3000',
        'dbo.ZZPDA_Rebuild_DLL',
        'dbo.tt_auto_data_acquisition_dpa',
        'dbo.Applications',
        'dbo.Settings',
        'dbo.Bmc_desktop_property_save',
        'dbo.ZZ_DVE_Item_calc_besoin_2',
        'dbo.ZZ_DVE_ITSSI',
        'dbo.BMC_trace',
        'dbo.BMC_Trace_dpa_item',
        'dbo.BMC_Trace_item_2',
        'dbo.TRACE_20120307_LPO',
        'dbo.ZZ_APS_monitor_row_OLD_SPE',
        'dbo.addres_link_201800807',
        'dbo.ph_prescriber_sav_20191203',
        'dbo.ph_physician_sav_20191203',
        'dbo.bkp_Item_inventory_20191210_AMA',
        'dbo.Bmc_application_default_backup_vesta_migration_lot3',
        'dbo.TT_Bmc_application_default_backup_vesta_migration_lot3'
        )

    
     ;
     PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Added columns matched to list ('+@pattern+'). '+REPLACE(REPLACE(CONVERT(VARCHAR(100), CONVERT(MONEY, @@rowcount), 1),',',''''),'.00','')+' row(s) affected.';
     
    FETCH NEXT FROM crsPatternInclude INTO @pattern, @toExclude
END

CLOSE crsPatternInclude
DEALLOCATE crsPatternInclude

--#endregion

--#region Look in text fields for match on the pattern
IF @searchInFields = 1
BEGIN 
    PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - populate from field content';

    INSERT INTO [#all_text_fields] ([table_schema],
                                    [table_name],
                                    [column_name],
                                    [data_type])
    SELECT 
        SCHEMA_NAME(t.[schema_id]),
        t.[name],
        c.[name],
        st.[name]
    FROM sys.[tables] t
        JOIN sys.columns c ON c.[object_id] = t.[object_id]
        JOIN sys.[types] st ON st.[system_type_id] = c.[system_type_id] AND st.[user_type_id] = c.[user_type_id]
    WHERE t.[type_desc] = 'USER_TABLE'
    AND c.[is_computed] = 0
    AND st.[collation_name] IS NOT NULL 
    AND c.[max_length] > 90
    ORDER BY SCHEMA_NAME(t.[schema_id]), t.[name], c.[name]
    ;

    DECLARE crsr_pattern_in_field CURSOR FAST_FORWARD READ_ONLY FOR 
        select [p].[pattern]
        FROM @Tblpattern p
        WHERE p.[toExclude] = 0

    OPEN crsr_pattern_in_field
    
    FETCH NEXT FROM crsr_pattern_in_field INTO @pattern

    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Looking for pattern '+@pattern;
    
        DECLARE crsr_in_field CURSOR FAST_FORWARD READ_ONLY FOR 
            SELECT [table_schema], [table_name], [column_name], [data_type]
            FROM [#all_text_fields]
        OPEN crsr_in_field
    
        FETCH NEXT FROM crsr_in_field INTO @schema_name, @table_name, @column_name, @data_type
    
        WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' -    Looking in '+@schema_name+'.'+@table_name+'.'+@column_name;
        
            SELECT @cmd = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@tplCheckInField,'@schema@', @schema_name), '@tbl@', @table_name), '@field@', @column_name), '@pattern@', @pattern), '@data_type@', @data_type);
            EXEC(@cmd)
            --PRINT @cmd
            FETCH NEXT FROM crsr_in_field INTO @schema_name, @table_name, @column_name, @data_type
        END
    
        CLOSE crsr_in_field
        DEALLOCATE crsr_in_field
    

        FETCH NEXT FROM crsr_pattern_in_field INTO @pattern
    END

    CLOSE crsr_pattern_in_field
    DEALLOCATE crsr_pattern_in_field
END 
--#endregion

--#region exclude results matched before
DECLARE crsPatternExclude CURSOR FAST_FORWARD READ_ONLY FOR 
    SELECT [pattern], [toExclude]
    FROM @Tblpattern c
    WHERE c.[toExclude] = 1

OPEN crsPatternExclude

FETCH NEXT FROM crsPatternExclude INTO @pattern, @toExclude

WHILE @@FETCH_STATUS = 0
BEGIN
    
    DELETE c
     FROM [#classification] c
     WHERE c.[COLUMN_NAME] LIKE @pattern
     AND @toExclude = 1
     ;
     PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Excluded columns from matched list ('+@pattern+'). '+REPLACE(REPLACE(CONVERT(VARCHAR(100), CONVERT(MONEY, @@rowcount), 1),',',''''),'.00','')+' row(s) affected.';
     
    FETCH NEXT FROM crsPatternExclude INTO @pattern, @toExclude
END

CLOSE crsPatternExclude
DEALLOCATE crsPatternExclude
--#endregion

--#region exlude from results tables with 0 rows

DELETE [c]
FROM [#classification] c
    JOIN (
        SELECT 
            SCHEMA_NAME(t.[schema_id]) AS [schema_name],
            t.name AS [table_name],
            SUM([ds].[row_count]) as [totalrows]
        FROM sys.dm_db_partition_stats ds
            JOIN sys.[tables] t ON ds.[object_id] = t.[object_id]
        GROUP BY t.[name], t.[schema_id]
        HAVING COUNT(1)=0
    )cnt ON cnt.[schema_name] = c.[table_schema] AND cnt.[table_name] = c.[table_name] 
;
PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Removed positive results from empty tables. '+REPLACE(REPLACE(CONVERT(VARCHAR(100), CONVERT(MONEY, @@rowcount), 1),',',''''),'.00','')+' row(s) affected.';

--#endregion

--#region Assign classification on matched columns
PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Assign classification on matched columns';

DECLARE crsr_classify_active CURSOR FAST_FORWARD READ_ONLY FOR 
    --SELECT 'ADD SENSITIVITY CLASSIFICATION TO ['+c.[table_schema]+'].['+c.[table_name]+'].['+c.[column_name]+'] WITH ( LABEL=''Confidential'', INFORMATION_TYPE=''Galenica Used Personal Informations'', RANK=High );' AS command
    SELECT 'EXEC dbo.setSensitivity @schemaName = '''+ c.[TABLE_SCHEMA] +''',  @tableName = '''+[c].[TABLE_NAME]+''', @columnName = '''+[c].[COLUMN_NAME]+''', @category = ''Galenica Used Personal Informations'', @sensitivity = ''Confidential'', @rank = ''High'', @removeClassification = 0 '
    FROM [#classification] c;

OPEN crsr_classify_active

FETCH NEXT FROM crsr_classify_active INTO @cmd

WHILE @@FETCH_STATUS = 0
BEGIN
    --PRINT @cmd
    EXEC(@cmd);
    FETCH NEXT FROM crsr_classify_active INTO @cmd
END

CLOSE crsr_classify_active
DEALLOCATE crsr_classify_active
--#endregion

--#region set classification "other - general" on every other columns
PRINT CONVERT(VARCHAR(20), CURRENT_TIMESTAMP, 114)+' - Assign classification on not matched columns';

IF @useSql2019Syntax = 0 BEGIN
    SET @cmd='
INSERT INTO #existing_classification([table_schema], [table_name], [column_name], [category], [sensibility], [rank])
SELECT
    CAST(schema_name(O.schema_id) AS VARCHAR(255))  AS schema_name,
    CAST(O.NAME AS VARCHAR(255))AS table_name ,
    CAST(C.NAME AS VARCHAR(255))AS column_name ,
    CAST(information_type AS VARCHAR(255)) as information_type ,
    CAST(sensitivity_label AS VARCHAR(255)) as sensitivity_label,
    NULL
FROM
    (
        SELECT
            IT.major_id,
            IT.minor_id,
            IT.information_type,
            L.sensitivity_label 
        FROM
        (
            SELECT
                major_id,
                minor_id,
                value AS information_type 
            FROM sys.extended_properties 
            WHERE NAME = ''sys_information_type_name''
        ) IT 
        FULL OUTER JOIN
        (
            SELECT
                major_id,
                minor_id,
                value AS sensitivity_label 
            FROM sys.extended_properties 
            WHERE NAME = ''sys_sensitivity_label_name''
        ) L 
        ON IT.major_id = L.major_id AND IT.minor_id = L.minor_id
    ) EP
    JOIN sys.objects O
    ON  EP.major_id = O.object_id 
    JOIN sys.columns C 
    ON  EP.major_id = C.object_id AND EP.minor_id = C.column_id
--WHERE CAST(information_type AS VARCHAR(255)) <> ''Galenica Used Personal Informations''
    ';
END 
ELSE 
BEGIN 
    SET @cmd='
INSERT INTO #existing_classification([table_schema], [table_name], [column_name], [category], [sensibility], [rank])
SELECT SCHEMA_NAME([O].[schema_id]) AS schema_name
        ,CAST(O.name AS VARCHAR(255)) AS table_name
        ,CAST(C.name AS VARCHAR(255)) AS column_name 
        ,CAST(sc.information_type AS VARCHAR(255)) as information_type
        ,CAST(sc.label AS VARCHAR(255)) as label 
        ,CAST(sc.rank_desc AS VARCHAR(255)) as rank_desc 
FROM sys.sensitivity_classifications sc
    JOIN sys.objects O
    ON [sc].[major_id] = O.object_id
    JOIN sys.columns C
    ON [sc].[major_id] = C.object_id
    AND [sc].[minor_id] = [C].[column_id]
--WHERE CAST(sc.information_type AS VARCHAR(255)) <> ''Galenica Used Personal Informations''
    ';
END 
EXEC(@cmd);

DECLARE crsr_classify_other CURSOR FAST_FORWARD READ_ONLY FOR 
    --SELECT 'ADD SENSITIVITY CLASSIFICATION TO ['+[ic].[TABLE_SCHEMA]+'].['+[ic].[TABLE_NAME]+'].['+[ic].[COLUMN_NAME]+']  WITH ( LABEL=''General'', INFORMATION_TYPE=''Other'', RANK=Low )'
    SELECT 'EXEC dbo.setSensitivity @schemaName = '''+ic.[TABLE_SCHEMA]+''',  @tableName = '''+[ic].[TABLE_NAME]+''', @columnName = '''+[ic].[COLUMN_NAME]+''', @category = ''Other'', @sensitivity = ''General'', @rank = ''Low'', @removeClassification='+CAST(@assignUnmatchedColumns ^ 1 AS NVARCHAR(2))+' '
    FROM [INFORMATION_SCHEMA].[COLUMNS] ic
        JOIN [INFORMATION_SCHEMA].[TABLES] it ON it.[TABLE_SCHEMA] = ic.[TABLE_SCHEMA] AND it.[TABLE_NAME] = ic.[TABLE_NAME]
    WHERE [it].[TABLE_TYPE] = 'BASE TABLE'
    AND NOT EXISTS(
        /* column is not classified */
        SELECT [ec].[table_schema],
               [ec].[table_name],
               [ec].[column_name],
               [ec].[category],
               [ec].[sensibility],
               [ec].[rank]
        FROM #existing_classification ec
        WHERE ec.[table_schema] = ic.[TABLE_SCHEMA]
        AND ec.[table_name] = ic.[TABLE_NAME]
        AND ec.[column_name] = ic.[COLUMN_NAME]
        AND ec.[category] = 'Galenica Used Personal Informations'
    )
    AND NOT EXISTS(
        /* ignore computed columns */
        SELECT 1
        FROM sys.[tables] t
            JOIN sys.columns c ON c.[object_id] = t.[object_id]
        WHERE c.[is_computed] = 1
        AND SCHEMA_NAME(t.[schema_id]) = ic.[TABLE_SCHEMA]
        AND t.[name] = ic.[TABLE_NAME]
        AND c.[name] = ic.[COLUMN_NAME]
    )
OPEN crsr_classify_other

FETCH NEXT FROM crsr_classify_other INTO @cmd

WHILE @@FETCH_STATUS = 0
BEGIN
    --PRINT @cmd;
    EXEC(@cmd);
    FETCH NEXT FROM crsr_classify_other INTO @cmd
END

CLOSE crsr_classify_other
DEALLOCATE crsr_classify_other
--#endregion

---- sql 2019 or later only
-- SELECT SCHEMA_NAME([O].[schema_id]) AS schema_name
--        ,CAST(O.name AS VARCHAR(255)) AS table_name
--        ,CAST(C.name AS VARCHAR(255)) AS column_name 
--        ,CAST(sc.information_type AS VARCHAR(255)) as information_type
--        ,CAST(sc.label AS VARCHAR(255)) as label 
--        ,CAST(sc.rank_desc AS VARCHAR(255)) as rank_desc 
--FROM sys.sensitivity_classifications sc
--    JOIN sys.objects O
--    ON [sc].[major_id] = O.object_id
--    JOIN sys.columns C
--    ON [sc].[major_id] = C.object_id
--    AND [sc].[minor_id] = [C].[column_id]


SELECT * 
FROM [#classification] c
ORDER BY [c].[table_schema], [c].[table_name], [c].[column_name]

IF OBJECT_ID('dbo.setSensitivity') IS NOT NULL 
BEGIN 
    DROP PROCEDURE dbo.setSensitivity;
END


