<html>
<head>
<title>SQL Relay - Extension Modules - Query Translation</title>
<link href="../css/styles.css" rel="stylesheet">
</head>
<body>

<span class="heading1">Query Translation Modules</span><br><br>

<ul>
<li><a href="#introduction">Introduction</a></li>
<li><a href="#available">Available Modules</a></li>
<li><a href="#custom">Custom Modules</a></li>
</ul>

<hr>

<br><a name="introduction"></a>
<span class="heading2">Introduction</span><br>

<p>Query Translation modules allow the SQL Relay server programs to alter queries before passing them to the database.</p>

<p>The <i>translations</i> section of the sqlrelay.conf file indicates which translation modules to load and what parameters to use when executing them.</p>

<blockquote>
@sqlrelay-translations-normalize.conf.html@
</blockquote>

<p>The <i>module</i> attribute specifies which module to load.</p>

<p>Module configurations may have attributes and/or nested tags.  How these elements are interpreted is module-specific.</p>

<p>Currently, all translation modules have an <i>enabled</i> parameter, allowing the module to be temporarily disabled.  If enabled="no" is configured, then the module is disabled.  If set to any other value, or omitted, then the module is enabled.</p>

<p>Translation modules can be "stacked".  Multiple modules may be loaded and multiple instances of the same type of module, with different configurations, may also be loaded.</p>

<blockquote>
@sqlrelay-translations-stacked.conf.html@
</blockquote>

<p>At startup, the SQL Relay server creates instances of the specified translations modules and initializes them.  When a query is run, the server passes the query to each module, in the order that they were specified in the config file.  If a module modifies the query, then that modified query is passed on to the next module.</p>

<br><a name="available"></a>
<span class="heading2">Available Modules</span><br>

<p>Currently, the following translation module is available:</p>

<b>
<ul>
<li>normalize</li>
</ul>
</b>

<br><br>
<span class="heading3">normalize</span><br>

<p>The normalize module performs the following operations on a query:</p>

<ul>
<li>Removes comments.</li>
<li>Converts all white-space characters to spaces, outside of quoted strings.</li>
<li>Converts multiple spaces into a single space, outside of quoted strings.</li>
<li>Removes whitespace from around operators, except for parentheses and asterisks (for now).</li>
<li>Converts everything to lower case, outside of quoted strings.</li>
<li>Converts static concatenations to equivalent strings.  Eg. converts 'he' || 'll' || 'o' to 'hello'.</li>
<li>...</li>
</ul>

<p>For example, the following query:</p>

<blockquote>
@normalize-before.sql.html@
</blockquote>

<p>Would be translated to:</p>

<blockquote>
@normalize-after.sql.html@
</blockquote>

<p>Normalizing a query is useful when also using <a href="filters.html">Query Filters</a> as it simplifies the patterns that have to be searched for.</p>

<br><a name="custom"></a>
<span class="heading2">Custom Modules</span><br>

<p>You can create your own custom query translation modules too.</p>

<p>SQL Relay provides a base class for query translation modules, called sqlrtranslation, defined in the header file: sqlrserver.h</p>

<blockquote>
@sqlrtranslation.h.html@
</blockquote>

<p>On non-Windows platforms, it's most likely installed in /usr/local/firstworks/include/sqlrelay if you built from source or /usr/include/sqlrelay if you installed a package.  On Windows platforms, it's most likely installed in C:\Program Files\Firstworks\include\sqlrelay.</p>

<p>The default implementaion of the constructor just sets the member variables <i>sqlts</i>, <i>parameters</i> and <i>debug</i> to the corresponding passed-in values.  <i>sqlts</i> is a pointer to an instance of the sqlrtranslations class, which provides various helper methods.  <i>parameters</i> is a representation of the XML tag in the sqlrelay.conf file that loaded the module.  <i>debug</i> is just a flag, indicating whether debug is requested or not.  The module should consult this flat and print out some debug if it is true.</p>

<p>By default, the destructor does nothing.</p>

<p>run() does nothing by default and returns true, indicating that no error occurred.</p>

<p>A custom module module must contain a class that inherits from sqlrtranslation, implements the necessary methods, and implements a function to return an instance of the class.</p>

<p>Lets say we want to create a custom translation module that translates the entire query to lower case.</p>

<p>We can create the file lowercase.cpp:</p>

<blockquote>
@sqlrtranslation-lowercase.cpp.html@
</blockquote>

<p>Here, the lowercase class inherits from sqlrtranslation.  The constructor just calls the parent constructor.  The run() method translates the query to lowercase and returns true.</p>

<p>Note the "new_sqlrtranslation_lowercase()" function which just allocates an instance of lowercase and returns it.  This function is essential to provide, and it is essential that it be named "new_sqlrtranslation_<i>modulename</i>" and take sqlrtranslations *, xmldomnode * and bool.  It is also essential that it be wrapped with an <i>extern "C"</i> clause to prevent it from being name-mangled by the compiler.</p>

<p>To build the module on a Linux or Unix system, run a command like:</p>

<blockquote><b>
gcc -shared `sqlrserver-config --cflags` `rudiments-config --cflags` -o sqlrtranslation_lowercase.so lowercase.cpp `sqlrserver-config --libs` `rudiments-config --libs`
</b></blockquote>

<p>This will create the file sqlrtranslation_lowercase.so</p>

<p>On Mac OSX, run a command like:</p>

<blockquote><b>
gcc -bundle `sqlrserver-config --cflags` `rudiments-config --cflags` -o sqlrtranslation_lowercase.bundle lowercase.cpp `sqlrserver-config --libs` `rudiments-config --libs`
</b></blockquote>

<p>This will create the sqlrtranslation_lowercase.bundle</p>

<p>On Windows, run commands like:</p>

<blockquote><b>
cl /I"C:\Program Files\Firstworks\include" /c lowercase.cpp<br>
link -out:sqlrtranslation_lowercase.dll /LIBPATH:"C:\Program Files\Firstworks\lib" libsqlrserver.lib librudiments.lib
</b></blockquote>

<p>This will create the sqlrtranslation_lowercase.dll</p>

<p>It is essential that the file be named "sqlrtranslation_<i>modulename</i>.<i>extension</i>".</p>

<p>To install the new module, copy it to the SQL Relay "modules" directory.  On non-Windows platforms, that is most likely /usr/local/firstworks/libexec/sqlrelay if you built from source, or /usr/libexec/sqlrelay if you installed a package.  On Windows platforms, that is most likely C:\Program Files\Firstworks\libexec\sqlrelay</p>

<p>To configure an instance of SQL Relay to use your module, you will need to update the sqlrelay.conf file to include a "translations" section:</p>

<blockquote>
@sqlrelay-translations-lowercase.conf.html@
</blockquote>

<p>The server will see the module="lowercase" attribute in the sqlrelay.conf file, look in the "modules" directory for sqlrtranslation_lowercase.<i>extension</i>, load it and and run the new_sqlrtranslation_lowercase() method to get an instance of the lowercase class and then run the various methods of that class.</p>

<p>This example module doesn't have any parameters, but if you create a module that does then you can access them via the the protected "parameters" member variable.  For example:</p>

<blockquote>
@sqlrtranslation-param.cpp.html@
</blockquote>

<p>Refer to the Rudiments documentation for more info on the <a href="http://rudiments.sourceforge.net/rudiments/classes/html/classxmldomnode.html">xmldomnode class</a>.</p>

</body>
</html>
