Technical Details

Technical details in order to create a translation rules project

Create the Visual Studio project

The first thing we need to set up is the Visual Studio project which will contain the additional translation rules. As mentioned before, these rules must be compiled into .dll files, therefore the output type of the project must be set as a Class Library and the target framework must be .NET 6. Here is an example of the .csproj file.

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Snowflake.SnowConvertExtensibility" Version="1.0.6" />
  </ItemGroup>
</Project>

As it can be seen, line 8 includes a NuGet called "Snowflake.SnowConvertExtensibility". This is an API we have created in order to make the coding process as easy as possible. It is the only package that needs to be referenced in the project file.

Next, comes a description of what the class needs to have in order to be dynamically loaded by SnowConvert

Translation Rule class

An additional translation rule is just a class written in C# with certain characteristics that make it able to be loaded at runtime by SnowConvert. There are two main things, both exposed in the SnowConvertExtensibility API, that the class needs to have, explained in the following two sub-sections.

ExportContract attribute

Translation rules are grouped into contracts. For example, when SnowConvert is translating IBM DB2 code to Snowflake, it will load all the translation rules that belong to the "Db2->Snow" contract. The string values of each contract are hidden from the developer and instead, an enumeration called TranslationRulesContracts is available in the SnowConvertExtensibility API.

Here is an example of the ExportContract attribute, which must be at the top of the class definition, for a translation rule that belongs to the contract mentioned above.

[ExportContract(TranslationRulesContracts.Db2ToSnow)]

Implement BaseExtensibleTranslationRule class

Every translation-rule class must extend from the BaseExtensibleTranslationRule class, which has the following signature:

public abstract class BaseExtensibleTranslationRule<TInputAst, TOutputAst> :
        BaseExtensibleTranslationRule<TInputAst, TOutputAst, ReplaceContext>, 
        ISnowConvertExtensibleRule
        where TInputAst : class, IAst
        where TOutputAst : class, IAst
  • TInputAst, represents the input AST type that the translation rule will take as a parameter.

  • TOUtputAst, represents the output AST type that the translation rule must return. Usually, it should be the same type as TInputAst.

Knowing the type of AST for these two generic parameters is a very important step in writing the translation rule. The section Working With ASTs explains how to find out the ASTs that the SnowConvert parser creates from a given SQL query.

By extending the BaseExtensibleTranslationRule class, it is necessary to implement two methods.

IsApplicable method

This method is in charge of deciding to which instances of the TInputAst class should the current translation rule apply. For example, the type SqlFunctionExpr represents all function calls in the entire source code SnowConvert is processing, but it might be the case that the translation rule should apply only to a subset of them. The IsApplicable method helps narrow the set of SqlFunctionExpr instances targeted by the translation rule. The signature of the method is the following:

/// <summary>
/// Returns if the current translation rule must apply to the given node. If this method 
/// returns true, the Replace method will be called with the given node. 
/// </summary>
/// <param name="inputNode">The node to test if the current translation rule applies.</param>
/// <returns>True, if the current translation rule applies to the given node, false otherwise.</returns>
protected abstract bool IsApplicable(TInputAst inputNode);

As shown above, the method returns a boolean. If the returned value is true, the Replace method will be executed for the current instance of the TDelegator class.

Replace method

This is the main method of the translation rule class, this is where the input AST must be transformed, replaced, or modified into a Snowflake equivalent AST. The signature of the method is the following:

/// <summary>
/// Main method of the translation rule, this is where the resulting node must be generated. 
/// The method must assign 'resultNode' because this is the resulting node of the translation rule. 
/// </summary>
/// <param name="inputNode">The input node.</param>
/// <param name="outputNode">The resulting node of the translation rule.</param>
protected abstract void Replace(TInputAst inputNode, out TOutputAst outputNode);

The implementation must assign the result out parameter before exiting.

Last updated