A macro can be be created as an in-project definition and its scope shall be within the selected scope in the project (per column, table, etc) and the macro shall be saved within the masking project file (.dvp) and be private to that project.
A macro can also be created as a Macro Component and saved separately as an independent XML text file that has global scope and can be shared with all project files.
All macros, those defined within a project and those saved as a component, are functionally identical. Only the scope differs.
The example below shows how to create a macro definition for a specific table.
Macro In-Project Definition
To create a macro definition within a project, first set focus to the scope that the macro shall apply. This can be done by first clicking on the relevant node in the Project explorer tree to set focus. Next, open the Masking tab in the main view and then click on the contained Macros tab.
For example, let's create a macro called #rate whose scope shall be at the table level for dbo.wages
First, the scope is selected in the Project tree (dbo.wages), and then we open the Masking->Macros tab that shows the macros defined for this scope.
Next, click on the 'Create...' button (or right-click on the table and choose 'Create'... from the popup menu).
Specify the Name of the macro. Here we enter the name rate. Notice that specifying the # character is optional on this form. If it is not specified then DataVeil shall automatically insert it.
To specify the Value of the macro, click on the 'Add...' button.
As shown below, the value of 20 has been entered.
Notice that it is possible to specify alternate values for a macro definition depending on which DBMS the masking project is running on. This is explained in detail further below. For now, accept Default for DBMS and click OK. The specified macro value for the DBMS is shown in the Create Macro dialog:
Click OK again to exit the macro creation dialog.
The macro definition now appears in the Macros tab for the scope in which it was created:
Macro Component Definition
As discussed above, an in-project macro definition is private to the project in which it was defined.
If it is required to share a macro definition among multiple projects then the macro should be created as a component. Functionally, in-project macro definitions and macro component definitions are identical. Only the scope is different.
Please refer to Macro Component for more details.
Example Usage in a User SQL Value Mask
Let's build on the example above that created the #rate macro and use it in a User SQL Value mask.
Suppose, it is required to mask an 'amount' column simply by multiplying the 'hours' column with a rate value.
Therefore, using the defined #rate macro, a User SQL Value mask could be created as follows:
After running the project the masked values are shown below. Considering that the #rate value had been defined above as 20, the first row shows that masked value is 800 and this indeed corresponds to the 'hours' value of 40 multiplied by #rate (20).
Example Usage in a Where Condition
Macros can be used in Where conditions. The example below also shows the usage of the built-in system macro #_column_name.
Suppose it is required to mask only those values whose original value was > 2000.00.
Therefore, instead of explicitly specifying the column name 'amount' in the Where condition, #_column_name can be used as shown below:
After running the project the masked values are shown below. It can be seen that the first row, whose amount did not satisfy the Where condition, was indeed preserved.
These are trivial examples whose objective is simply to introduce the basics of creating and using macros. The real power comes from using macros on a broader scale, such as when many columns need to reference a common value that may change in future, or a common base value may need to be adjusted according to scope, recursion and especially when combined with Macro Components and usage within Mask Components.
Verifying Resolved Macro Values
The resolved values of macros in a masking project can be verified on the DataVeil logger, Execution Control Panel and Masking Report.
Execution Control Panel
Alternate Macro Values Per DBMS
A macro definition can specify alternate values according to the DBMS on which it is being used.
For instance, the DataVeil system-defined macro #_is_json is implemented internally as:
Therefore, if a masking project contains a mask that is only to select valid JSON records for masking then the column's Where condition could simply specify #_is_json
When a project is masking Azure SQL DB or SQL Server then this macro shall return the value (ISJSON(#_column_name) > 0). When a project is masking Oracle then this macro shall return the value (#_column_name IS JSON).
Note: If there is no defined Value for DBMS Default and the macro is used on a DBMS whose type also does not appear in the DBMS column then the DataVeil compiler shall return an error. This would be the case if #_is_json shown above was to be used on MySQL as it does not appear in the DBMS column and Default has also not been defined.
DataVeil macros are recursive.
This means that a macro can reference other macros which can also reference other macros and so on.
When the DataVeil compiler encounters a macro that references another macro, the compiler shall try to resolve the other macro by starting to search from the same level as the initial usage of the macro.
For example, suppose a macro #payment is defined at table level and this macro is used in a User SQL Value mask in a column of that table. The value of #payment is 20 * #overtime.
When the compiler expands #payment in the column mask and in the process encounters another macro #overtime, the compiler immediately returns to the node where the initial macro was used and not where the macro was defined. In this case the compiler would return to the column.
From there, the compiler tries to resolve this next macro (#overtime) by searching for that macro name in the column's macro definitions. If found it uses it otherwise the search moves up to the next level, being the parent table. If the macro definition is not found there then the search moves up to the parent database, and then the project level and finally the component level is searched. If not found anywhere then an error is returned.
Suppose that the #overtime macro definition was eventually found at the component level. and that the value was 1.5 * #region_adjust. The compiler would now return to the node of initial usage, which would be back to the column containing the mask using #payment, and begin searching for the macro definition of #region_adjust.