Summary

Class:CBAM.SQL.Implementation.DefaultOrdinalSQLCache`1
Assembly:CBAM.SQL.Implementation
File(s):/repo-dir/contents/Source/Code/CBAM.SQL.Implementation/Meta.cs
Covered lines:9
Uncovered lines:6
Coverable lines:15
Total lines:1249
Line coverage:60%
Branch coverage:16.6%

Coverage History

Metrics

MethodCyclomatic complexity NPath complexity Sequence coverage Branch coverage
.ctor(...)201%0.5%
.ctor(...)101%0%
GetSQL(...)400%0%

File(s)

/repo-dir/contents/Source/Code/CBAM.SQL.Implementation/Meta.cs

#LineLine coverage
 1/*
 2 * Copyright 2017 Stanislav Muhametsin. All rights Reserved.
 3 *
 4 * Licensed  under the  Apache License,  Version 2.0  (the "License");
 5 * you may not use  this file  except in  compliance with the License.
 6 * You may obtain a copy of the License at
 7 *
 8 *   http://www.apache.org/licenses/LICENSE-2.0
 9 *
 10 * Unless required by applicable law or agreed to in writing, software
 11 * distributed  under the  License is distributed on an "AS IS" BASIS,
 12 * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
 13 * implied.
 14 *
 15 * See the License for the specific language governing permissions and
 16 * limitations under the License.
 17 */
 18
 19using CBAM.Abstractions;
 20using CBAM.SQL;
 21using System;
 22using System.Collections.Generic;
 23using System.Text;
 24using System.Threading;
 25using System.Threading.Tasks;
 26using UtilPack;
 27using UtilPack.TabularData;
 28
 29namespace CBAM.SQL.Implementation
 30{
 31   /// <summary>
 32   /// This class provides default implementation for <see cref="DatabaseMetadata"/> interface, using the <see cref="SQL
 33   /// </summary>
 34   public abstract class DatabaseMetadataImpl : DatabaseMetadata
 35   {
 36
 37      /// <summary>
 38      /// Initializes a new instance of <see cref="DatabaseMetadataImpl"/> with given <see cref="SQLConnectionVendorFunc
 39      /// </summary>
 40      /// <param name="vendorFunctionality">The <see cref="SQLConnectionVendorFunctionality"/> to use when creating <see
 41      /// <param name="name">The name of the database.</param>
 42      /// <exception cref="ArgumentNullException">If <paramref name="vendorFunctionality"/> is <c>null</c>.</exception>
 43      public DatabaseMetadataImpl(
 44         SQLConnectionVendorFunctionality vendorFunctionality,
 45         String name
 46         )
 47      {
 48         this.VendorFunctionality = ArgumentValidator.ValidateNotNull( nameof( vendorFunctionality ), vendorFunctionalit
 49         this.Name = name;
 50      }
 51
 52      /// <summary>
 53      /// Implements <see cref="DatabaseMetadata.Name"/> and gets the name of the database this connection is connected 
 54      /// </summary>
 55      /// <value>The name of the database this connection is connected to.</value>
 56      public String Name { get; }
 57
 58      /// <summary>
 59      /// Helper property to get the <see cref="SQLConnectionVendorFunctionality"/> of this <see cref="DatabaseMetadataI
 60      /// </summary>
 61      /// <value>The <see cref="SQLConnectionVendorFunctionality"/> of this <see cref="DatabaseMetadataImpl"/>.</value>
 62      protected SQLConnectionVendorFunctionality VendorFunctionality { get; }
 63
 64      /// <summary>
 65      /// Implements <see cref="DatabaseMetadata.CreateSchemaSearch(String)"/> method by calling <see cref="CreateSQLFor
 66      /// </summary>
 67      /// <param name="schemaNamePattern">The schema name pattern. If not <c>null</c> or empty, will narrow down search 
 68      /// <returns>An <see cref="IAsyncEnumerable{T}"/> which can be executed to search the schema information from the 
 69      public SQLStatementBuilder CreateSchemaSearch( String schemaNamePattern )
 70      {
 71         return this.SetSubsequentNonNullPatterns(
 72            this.VendorFunctionality.CreateStatementBuilder( this.CreateSQLForSchemaSearch( schemaNamePattern ) ),
 73            schemaNamePattern
 74            );
 75      }
 76
 77      /// <summary>
 78      /// Implements <see cref="DatabaseMetadata.CreateTableSearch(String, String, TableType[])"/> method by calling <se
 79      /// </summary>
 80      /// <param name="schemaNamePattern">The schema name pattern. If not <c>null</c> or empty, will narrow down search 
 81      /// <param name="tableNamePattern">The table name pattern. If not <c>null</c> or empty, will narrow down search re
 82      /// <param name="tableTypes">The table types. If not <c>null</c> and not empty, can be used to further narrow down
 83      /// <returns>An <see cref="SQLStatementBuilder"/> which can be used to search the table information from the datab
 84      public SQLStatementBuilder CreateTableSearch( String schemaNamePattern, String tableNamePattern, TableType[] table
 85      {
 86         var retVal = this.VendorFunctionality.CreateStatementBuilder( this.CreateSQLForTableSearch( schemaNamePattern, 
 87         var idx = 0;
 88         this.SetSubsequentNonNullPatterns( retVal, ref idx, schemaNamePattern, tableNamePattern );
 89         foreach ( var tType in tableTypes )
 90         {
 91            (var obj, var type) = this.GetParameterInfoForTableType( tType );
 92            retVal.SetParameterObjectWithType( idx++, obj, type );
 93         }
 94         return retVal;
 95      }
 96
 97      /// <summary>
 98      /// Implements <see cref="DatabaseMetadata.CreateColumnSearch(String, String, String)"/> method by calling <see cr
 99      /// </summary>
 100      /// <param name="schemaNamePattern">The schema name pattern. If not <c>null</c> or empty, will narrow down search 
 101      /// <param name="tableNamePattern">The table name pattern. If not <c>null</c> or empty, will narrow down search re
 102      /// <param name="columnNamePattern">The column name pattern. If not <c>null</c> or empty, will narrow down search 
 103      /// <returns>An <see cref="SQLStatementBuilder"/> which can be used to search the table column information from th
 104      public SQLStatementBuilder CreateColumnSearch( String schemaNamePattern, String tableNamePattern, String columnNam
 105      {
 106         return this.SetSubsequentNonNullPatterns(
 107            this.VendorFunctionality.CreateStatementBuilder( this.CreateSQLForColumnSearch( schemaNamePattern, tableName
 108            schemaNamePattern,
 109            tableNamePattern,
 110            columnNamePattern
 111            );
 112      }
 113
 114      /// <summary>
 115      /// Implements <see cref="DatabaseMetadata.CreatePrimaryKeySearch(String, String)"/> method by calling <see cref="
 116      /// </summary>
 117      /// <param name="schemaNamePattern">The schema name pattern. If not <c>null</c> or empty, will narrow down search 
 118      /// <param name="tableNamePattern">The table name pattern. If not <c>null</c> or empty, will narrow down search re
 119      /// <returns>An <see cref="SQLStatementBuilder"/> which can be used to search the table primary key information fr
 120      public SQLStatementBuilder CreatePrimaryKeySearch( String schemaNamePattern, String tableNamePattern )
 121      {
 122         return this.SetSubsequentNonNullPatterns(
 123            this.VendorFunctionality.CreateStatementBuilder( this.CreateSQLForPrimaryKeySearch( schemaNamePattern, table
 124            schemaNamePattern,
 125            tableNamePattern
 126            );
 127      }
 128
 129      /// <summary>
 130      /// Implements <see cref="DatabaseMetadata.CreateForeignKeySearch(String, String, String, String)"/> method by cal
 131      /// </summary>
 132      /// <param name="primarySchemaName">The schema name of the table containing primary key. If not <c>null</c> or emp
 133      /// <param name="primaryTableName">The name of the table containing primary key. If not <c>null</c> or empty, will
 134      /// <param name="foreignSchemaName">The schema name of the table containing foreign key. If not <c>null</c> or emp
 135      /// <param name="foreignTableName">The name of the table containing foreign key. If not <c>null</c> or empty, will
 136      /// <returns>An <see cref="SQLStatementBuilder"/> which can be used to search the table foreign key information fr
 137      public SQLStatementBuilder CreateForeignKeySearch( String primarySchemaName, String primaryTableName, String forei
 138      {
 139         return this.SetSubsequentNonNullPatterns(
 140            this.VendorFunctionality.CreateStatementBuilder( this.CreateSQLForForeignKeySearch( primarySchemaName, prima
 141            primarySchemaName,
 142            primaryTableName,
 143            foreignSchemaName,
 144            foreignTableName
 145            );
 146      }
 147
 148      /// <summary>
 149      /// Helper method to set all non-<c>null</c> strings from given array of strings as parameters to given <see cref=
 150      /// </summary>
 151      /// <param name="stmt">The <see cref="SQLStatementBuilder"/>.</param>
 152      /// <param name="values">The string array to set parameters from.</param>
 153      /// <returns>The <paramref name="stmt"/>.</returns>
 154      /// <exception cref="NullReferenceException">If either of <paramref name="stmt"/> or <paramref name="values"/> is 
 155      protected SQLStatementBuilder SetSubsequentNonNullPatterns( SQLStatementBuilder stmt, params String[] values )
 156      {
 157         var idx = 0;
 158         this.SetSubsequentNonNullPatterns( stmt, ref idx, values );
 159         return stmt;
 160      }
 161
 162      /// <summary>
 163      /// Helper method to set all non-<c>null</c> strings from given array of strings as parameters to given <see cref=
 164      /// </summary>
 165      /// <param name="stmt">The <see cref="SQLStatementBuilder"/>.</param>
 166      /// <param name="idx">The index where to start setting parameters in given <paramref name="stmt"/>.</param>
 167      /// <param name="values">The string array to set parameters from.</param>
 168      /// <exception cref="NullReferenceException">If either of <paramref name="stmt"/> or <paramref name="values"/> is 
 169      protected void SetSubsequentNonNullPatterns( SQLStatementBuilder stmt, ref Int32 idx, params String[] values )
 170      {
 171         foreach ( var str in values )
 172         {
 173            if ( str != null )
 174            {
 175               (var obj, var type) = this.GetParameterInfoForPattern( str );
 176               stmt.SetParameterObjectWithType( idx++, obj, type );
 177            }
 178         }
 179      }
 180
 181      /// <summary>
 182      /// Implements <see cref="DatabaseMetadata.ExtractSchemaMetadataAsync"/> by checking that <paramref name="row"/> i
 183      /// </summary>
 184      /// <param name="row">The data row encountered during processing query produced by <see cref="CreateSchemaSearch"/
 185      /// <returns>Result of <see cref="DoExtractSchemaMetadataAsync"/> method.</returns>
 186      /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <c>null</c>.</exception>
 187      public ValueTask<SchemaMetadata> ExtractSchemaMetadataAsync( AsyncDataRow row )
 188      {
 189         return this.DoExtractSchemaMetadataAsync( ArgumentValidator.ValidateNotNull( nameof( row ), row ) );
 190      }
 191
 192      /// <summary>
 193      /// Implements <see cref="DatabaseMetadata.ExtractTableMetadataAsync"/> by checking that <paramref name="row"/> is
 194      /// </summary>
 195      /// <param name="row">The data row encountered during processing query produced by <see cref="CreateTableSearch"/>
 196      /// <returns>Result of <see cref="DoExtractTableMetadataAsync"/> method.</returns>
 197      /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <c>null</c>.</exception>
 198      public ValueTask<TableMetadata> ExtractTableMetadataAsync( AsyncDataRow row )
 199      {
 200         return this.DoExtractTableMetadataAsync( ArgumentValidator.ValidateNotNull( nameof( row ), row ) );
 201      }
 202
 203      /// <summary>
 204      /// Implements <see cref="DatabaseMetadata.ExtractColumnMetadataAsync"/> by checking that <paramref name="row"/> i
 205      /// </summary>
 206      /// <param name="row">The data row encountered during processing query produced by <see cref="CreateColumnSearch"/
 207      /// <returns>Result of <see cref="DoExtractColumnMetadataAsync"/> method.</returns>
 208      /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <c>null</c>.</exception>
 209      public ValueTask<ColumnMetadata> ExtractColumnMetadataAsync( AsyncDataRow row )
 210      {
 211         return this.DoExtractColumnMetadataAsync( ArgumentValidator.ValidateNotNull( nameof( row ), row ) );
 212      }
 213
 214      /// <summary>
 215      /// Implements <see cref="DatabaseMetadata.ExtractPrimaryKeyMetadataAsync"/> by checking that <paramref name="row"
 216      /// </summary>
 217      /// <param name="row">The data row encountered during processing query produced by <see cref="CreatePrimaryKeySear
 218      /// <returns>Result of <see cref="DoExtractPrimaryKeyMetadataAsync"/> method.</returns>
 219      /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <c>null</c>.</exception>
 220      public ValueTask<PrimaryKeyMetadata> ExtractPrimaryKeyMetadataAsync( AsyncDataRow row )
 221      {
 222         return this.DoExtractPrimaryKeyMetadataAsync( ArgumentValidator.ValidateNotNull( nameof( row ), row ) );
 223      }
 224
 225      /// <summary>
 226      /// Implements <see cref="DatabaseMetadata.ExtractForeignKeyMetadataAsync"/> by checking that <paramref name="row"
 227      /// </summary>
 228      /// <param name="row">The data row encountered during processing query produced by <see cref="CreateForeignKeySear
 229      /// <returns>Result of <see cref="DoExtractForeignKeyMetadataAsync"/> method.</returns>
 230      /// <exception cref="ArgumentNullException">If <paramref name="row"/> is <c>null</c>.</exception>
 231      public ValueTask<ForeignKeyMetadata> ExtractForeignKeyMetadataAsync( AsyncDataRow row )
 232      {
 233         return this.DoExtractForeignKeyMetadataAsync( ArgumentValidator.ValidateNotNull( nameof( row ), row ) );
 234      }
 235
 236      /// <summary>
 237      /// Derived classes should implement this method to create new instance of <see cref="SchemaMetadata"/> from <see 
 238      /// When called by <see cref="ExtractSchemaMetadataAsync(AsyncDataRow)"/>, the <paramref name="row"/> is never <c>
 239      /// </summary>
 240      /// <param name="row">The <see cref="AsyncDataRow"/> originating from query produced by <see cref="CreateSchemaSea
 241      /// <returns>Possibly asynchronously returns a new instance of <see cref="SchemaMetadata"/> with information based
 242      protected abstract ValueTask<SchemaMetadata> DoExtractSchemaMetadataAsync( AsyncDataRow row );
 243
 244      /// <summary>
 245      /// Derived classes should implement this method to create new instance of <see cref="TableMetadata"/> from <see c
 246      /// When called by <see cref="ExtractTableMetadataAsync(AsyncDataRow)"/>, the <paramref name="row"/> is never <c>n
 247      /// </summary>
 248      /// <param name="row">The <see cref="AsyncDataRow"/> originating from query produced by <see cref="CreateTableSear
 249      /// <returns>Possibly asynchronously returns a new instance of <see cref="TableMetadata"/> with information based 
 250      protected abstract ValueTask<TableMetadata> DoExtractTableMetadataAsync( AsyncDataRow row );
 251
 252      /// <summary>
 253      /// Derived classes should implement this method to create new instance of <see cref="ColumnMetadata"/> from <see 
 254      /// When called by <see cref="ExtractColumnMetadataAsync(AsyncDataRow)"/>, the <paramref name="row"/> is never <c>
 255      /// </summary>
 256      /// <param name="row">The <see cref="AsyncDataRow"/> originating from query produced by <see cref="CreateColumnSea
 257      /// <returns>Possibly asynchronously returns a new instance of <see cref="ColumnMetadata"/> with information based
 258      protected abstract ValueTask<ColumnMetadata> DoExtractColumnMetadataAsync( AsyncDataRow row );
 259
 260      /// <summary>
 261      /// Derived classes should implement this method to create new instance of <see cref="PrimaryKeyMetadata"/> from <
 262      /// When called by <see cref="ExtractPrimaryKeyMetadataAsync(AsyncDataRow)"/>, the <paramref name="row"/> is never
 263      /// </summary>
 264      /// <param name="row">The <see cref="AsyncDataRow"/> originating from query produced by <see cref="CreatePrimaryKe
 265      /// <returns>Possibly asynchronously returns a new instance of <see cref="PrimaryKeyMetadata"/> with information b
 266      protected abstract ValueTask<PrimaryKeyMetadata> DoExtractPrimaryKeyMetadataAsync( AsyncDataRow row );
 267
 268      /// <summary>
 269      /// Derived classes should implement this method to create new instance of <see cref="ForeignKeyMetadata"/> from <
 270      /// When called by <see cref="ExtractForeignKeyMetadataAsync(AsyncDataRow)"/>, the <paramref name="row"/> is never
 271      /// </summary>
 272      /// <param name="row">The <see cref="AsyncDataRow"/> originating from query produced by <see cref="CreateForeignKe
 273      /// <returns>Possibly asynchronously returns a new instance of <see cref="ForeignKeyMetadata"/> with information b
 274      protected abstract ValueTask<ForeignKeyMetadata> DoExtractForeignKeyMetadataAsync( AsyncDataRow row );
 275
 276      /// <summary>
 277      /// Derived classes should implement this method to create textual SQL statement string for schema search with giv
 278      /// Returned SQL statement should have legal parameter character (<c>?</c>) for every non-<c>null</c> string given
 279      /// </summary>
 280      /// <param name="schemaNamePattern">The pattern for schema name.</param>
 281      /// <returns>SQL statement with legal parameter character (<c>?</c>) for every non-<c>null</c> string given to thi
 282      protected abstract String CreateSQLForSchemaSearch( String schemaNamePattern );
 283
 284      /// <summary>
 285      /// Derived classes should implement this method to create textual SQL statement string for table search with give
 286      /// Returned SQL statement should have legal parameter character (<c>?</c>) for every non-<c>null</c> string given
 287      /// Additionally, the parameter characters for each value in <paramref name="tableTypes"/> should be present after
 288      /// </summary>
 289      /// <param name="schemaNamePattern">The pattern for schema name.</param>
 290      /// <param name="tableNamePattern">The pattern for table name.</param>
 291      /// <param name="tableTypes">The array of <see cref="TableType"/> enumerations describing the type of the table.</
 292      /// <returns>SQL statement with legal parameter character (<c>?</c>) for every non-<c>null</c> string given to thi
 293      protected abstract String CreateSQLForTableSearch( String schemaNamePattern, String tableNamePattern, TableType[] 
 294
 295      /// <summary>
 296      /// Derived classes should implement this method to create textual SQL statement string for column search with giv
 297      /// Returned SQL statement should have legal parameter character (<c>?</c>) for every non-<c>null</c> string given
 298      /// </summary>
 299      /// <param name="schemaNamePattern">The pattern for schema name.</param>
 300      /// <param name="tableNamePattern">The pattern for table name.</param>
 301      /// <param name="columnNamePattern">The pattern for column name.</param>
 302      /// <returns>SQL statement with legal parameter character (<c>?</c>) for every non-<c>null</c> string given to thi
 303      protected abstract String CreateSQLForColumnSearch( String schemaNamePattern, String tableNamePattern, String colu
 304
 305      /// <summary>
 306      /// Derived classes should implement this method to create textual SQL statement string for column search with giv
 307      /// Returned SQL statement should have legal parameter character (<c>?</c>) for every non-<c>null</c> string given
 308      /// </summary>
 309      /// <param name="schemaNamePattern">The pattern for schema name.</param>
 310      /// <param name="tableNamePattern">The pattern for table name.</param>
 311      /// <returns>SQL statement with legal parameter character (<c>?</c>) for every non-<c>null</c> string given to thi
 312      protected abstract String CreateSQLForPrimaryKeySearch( String schemaNamePattern, String tableNamePattern );
 313
 314      /// <summary>
 315      /// Derived classes should implement this method to create textual SQL statement string for column search with giv
 316      /// Returned SQL statement should have legal parameter character (<c>?</c>) for every non-<c>null</c> string given
 317      /// </summary>
 318      /// <param name="primarySchemaName">The pattern for schema name of the table holding primary key.</param>
 319      /// <param name="primaryTableName">The pattern for table name of the table holding primary key.</param>
 320      /// <param name="foreignSchemaName">The pattern for schema name of the table holding foreign key.</param>
 321      /// <param name="foreignTableName">The pattern for table name of the table holding foreign key.</param>
 322      /// <returns>SQL statement with legal parameter character (<c>?</c>) for every non-<c>null</c> string given to thi
 323      protected abstract String CreateSQLForForeignKeySearch( String primarySchemaName, String primaryTableName, String 
 324
 325      /// <summary>
 326      /// Derived classes should implement this method to get parameter information for <see cref="SQLStatementBuilder"/
 327      /// </summary>
 328      /// <param name="tableType">The <see cref="TableType"/>.</param>
 329      /// <returns>A tuple of value and type of the value for <paramref name="tableType"/>. If value is not <c>null</c>,
 330      protected abstract (Object, Type) GetParameterInfoForTableType( TableType tableType );
 331
 332      /// <summary>
 333      /// Provides default overridable implementation for getting parameter information for <see cref="SQLStatementBuild
 334      /// </summary>
 335      /// <param name="pattern">The name pattern.</param>
 336      /// <returns>A tuple of value and type of the value for <paramref name="pattern"/>. If value is not <c>null</c>, t
 337      protected virtual (Object, Type) GetParameterInfoForPattern( String pattern )
 338      {
 339         return (pattern, null);
 340      }
 341   }
 342
 343   /// <summary>
 344   /// This interface provides API for getting <see cref="OrdinalSQLCache"/>s for SQL statements used by <see cref="Data
 345   /// </summary>
 346   /// <seealso cref="OrdinalSQLCache"/>
 347   /// <seealso cref="OrdinalSQLCache{T}"/>
 348   /// <seealso cref="SQLCachingDatabaseMetadataImpl"/>
 349   public interface DatabaseMetadataSQLCache
 350   {
 351      /// <summary>
 352      /// Gets the <see cref="OrdinalSQLCache"/> used for schema searches.
 353      /// </summary>
 354      /// <value>The <see cref="OrdinalSQLCache"/> used for schema searches.</value>
 355      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForSchemaSearch(String)"/>
 356      OrdinalSQLCache SchemaSearchCache { get; }
 357
 358      /// <summary>
 359      /// Gets the <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array is m
 360      /// </summary>
 361      /// <value>The <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array is
 362      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForTableSearch"/>
 363      OrdinalSQLCache<TableType?> TableSearchCache { get; }
 364
 365      /// <summary>
 366      /// Gets the <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array has 
 367      /// </summary>
 368      /// <value>The <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array ha
 369      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForTableSearch"/>
 370      OrdinalSQLCache<TableType[]> TableSearchCacheForMultipleTableTypes { get; }
 371
 372      /// <summary>
 373      /// Gets the <see cref="OrdinalSQLCache"/> used for column searches.
 374      /// </summary>
 375      /// <value>The <see cref="OrdinalSQLCache"/> used for column searches.</value>
 376      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForColumnSearch"/>
 377      OrdinalSQLCache ColumnSearchCache { get; }
 378
 379      /// <summary>
 380      /// Gets the <see cref="OrdinalSQLCache"/> used for primary key searches.
 381      /// </summary>
 382      /// <value>The <see cref="OrdinalSQLCache"/> used for primary key searches.</value>
 383      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForPrimaryKeySearch"/>
 384      OrdinalSQLCache PrimaryKeySearchCache { get; }
 385
 386      /// <summary>
 387      /// Gets the <see cref="OrdinalSQLCache"/> used for foreign key searches.
 388      /// </summary>
 389      /// <value>The <see cref="OrdinalSQLCache"/> used for foreign key searches.</value>
 390      /// <seealso cref="SQLCachingDatabaseMetadataImpl.CreateSQLForForeignKeySearch"/>
 391      OrdinalSQLCache ForeignKeySearchCache { get; }
 392   }
 393
 394   /// <summary>
 395   /// This class provides default implementation for <see cref="DatabaseMetadataSQLCache"/> by using <see cref="Default
 396   /// </summary>
 397   public class DefaultDatabaseMetadataSQLCache : DatabaseMetadataSQLCache
 398   {
 399      /// <summary>
 400      /// Creates new instance of <see cref="DefaultDatabaseMetadataSQLCache"/> with given parameters.
 401      /// </summary>
 402      /// <param name="schemaSearchSQLFactory">The factory callback for <see cref="DefaultOrdinalSQLCache"/> acting as <
 403      /// <param name="tableSearchSQLFactory">The factory callback for <see cref="DefaultOrdinalSQLCache{T}"/> acting as
 404      /// <param name="tableSearchForMultipleTableTypesSQLFactory">The factory callback for <see cref="DefaultOrdinalSQL
 405      /// <param name="columnSearchSQLFactory">The factory callback for <see cref="DefaultOrdinalSQLCache"/> acting as <
 406      /// <param name="primaryKeySearchSQLFactory">The factory callback for <see cref="DefaultOrdinalSQLCache"/> acting 
 407      /// <param name="foreignKeySearchSQLFactory">The factory callback for <see cref="DefaultOrdinalSQLCache"/> acting 
 408      /// <exception cref="ArgumentNullException">If any of <paramref name="schemaSearchSQLFactory"/>, <paramref name="t
 409      /// <remarks>
 410      /// This constructor will create the <see cref="DefaultOrdinalSQLCache"/> instances with enough room to cover need
 411      /// </remarks>
 412      public DefaultDatabaseMetadataSQLCache(
 413         Func<Int32, String> schemaSearchSQLFactory, // 0 - (schemaNamePattern Missing), 1 - (schemaNamePattern Present)
 414         Func<Int32, TableType?, String> tableSearchSQLFactory, // 0 - (schemaNamePattern M, tableNamePattern M, tableTy
 415         Func<Int32, TableType[], (String, Boolean)> tableSearchForMultipleTableTypesSQLFactory,
 416         Func<Int32, String> columnSearchSQLFactory,
 417         Func<Int32, String> primaryKeySearchSQLFactory,
 418         Func<Int32, String> foreignKeySearchSQLFactory
 419         )
 420      {
 421         this.SchemaSearchCache = new DefaultOrdinalSQLCache( 1 << 1, schemaSearchSQLFactory );
 422         this.TableSearchCache = new DefaultOrdinalSQLCache<TableType?>( 1 << 3, tableSearchSQLFactory );
 423         this.TableSearchCacheForMultipleTableTypes = new DefaultOrdinalSQLCache<TableType[]>( 1 << 2, tableSearchForMul
 424         this.ColumnSearchCache = new DefaultOrdinalSQLCache( 1 << 3, columnSearchSQLFactory );
 425         this.PrimaryKeySearchCache = new DefaultOrdinalSQLCache( 1 << 2, primaryKeySearchSQLFactory );
 426         this.ForeignKeySearchCache = new DefaultOrdinalSQLCache( 1 << 4, foreignKeySearchSQLFactory );
 427      }
 428
 429      /// <summary>
 430      /// Implements <see cref="DatabaseMetadataSQLCache.SchemaSearchCache"/> and gets the <see cref="OrdinalSQLCache"/>
 431      /// </summary>
 432      /// <value>The <see cref="OrdinalSQLCache"/> used for schema searches.</value>
 433      public OrdinalSQLCache SchemaSearchCache { get; }
 434
 435      /// <summary>
 436      /// Implements <see cref="DatabaseMetadataSQLCache.TableSearchCache"/> and gets the <see cref="OrdinalSQLCache{T}"
 437      /// </summary>
 438      /// <value>The <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array is
 439      public OrdinalSQLCache<TableType?> TableSearchCache { get; }
 440
 441      /// <summary>
 442      /// Implements <see cref="DatabaseMetadataSQLCache.TableSearchCacheForMultipleTableTypes"/> and gets the <see cref
 443      /// </summary>
 444      /// <value>The <see cref="OrdinalSQLCache{T}"/> used for table searches, when the <see cref="TableType"/> array ha
 445      public OrdinalSQLCache<TableType[]> TableSearchCacheForMultipleTableTypes { get; }
 446
 447      /// <summary>
 448      /// Implements <see cref="DatabaseMetadataSQLCache.ColumnSearchCache"/> and gets the <see cref="OrdinalSQLCache"/>
 449      /// </summary>
 450      /// <value>The <see cref="OrdinalSQLCache"/> used for column searches.</value>
 451      public OrdinalSQLCache ColumnSearchCache { get; }
 452
 453      /// <summary>
 454      /// Implements <see cref="DatabaseMetadataSQLCache.PrimaryKeySearchCache"/> and gets the <see cref="OrdinalSQLCach
 455      /// </summary>
 456      /// <value>The <see cref="OrdinalSQLCache"/> used for primary key searches.</value>
 457      public OrdinalSQLCache PrimaryKeySearchCache { get; }
 458
 459      /// <summary>
 460      /// Implements <see cref="DatabaseMetadataSQLCache.ForeignKeySearchCache"/> and gets the <see cref="OrdinalSQLCach
 461      /// </summary>
 462      /// <value>The <see cref="OrdinalSQLCache"/> used for foreign key searches.</value>
 463      public OrdinalSQLCache ForeignKeySearchCache { get; }
 464   }
 465
 466   /// <summary>
 467   /// Implements caching SQL statements based on ordinal number, which is binary sequence of null and non-null paramete
 468   /// </summary>
 469   /// <remarks>
 470   /// <para>The "original method" here is one of the following:
 471   /// <list type="bullet">
 472   /// <item><description><see cref="DatabaseMetadata.CreateSchemaSearch"/>,</description></item>
 473   /// <item><description><see cref="DatabaseMetadata.CreateTableSearch"/>,</description></item>
 474   /// <item><description><see cref="DatabaseMetadata.CreateColumnSearch"/>,</description></item>
 475   /// <item><description><see cref="DatabaseMetadata.CreatePrimaryKeySearch"/>, or</description></item>
 476   /// <item><description><see cref="DatabaseMetadata.CreateForeignKeySearch"/>.</description></item>
 477   /// </list>
 478   /// </para>
 479   /// <para>
 480   /// The ordinal number is generated so that it covers all permutations of method parameters being <c>null</c> or not 
 481   /// For example, the <see cref="DatabaseMetadata.CreateSchemaSearch"/> method has one parameter, so nullability of it
 482   /// This bit is <c>0</c> when the parameter is <c>null</c>, and <c>1</c> when parameter is not <c>null</c>.
 483   /// Therefore, the possible permutation order numbers are <c>0</c> and <c>1</c>.
 484   /// </para>
 485   /// <para>
 486   /// A little more complex example: <see cref="DatabaseMetadata.CreateColumnSearch"/>, which has three parameters, so 
 487   /// <list type="table">
 488   ///
 489   /// <listheader>
 490   /// <term>First parameter</term>
 491   /// <term>Second parameter</term>
 492   /// <term>Third parameter</term>
 493   /// <term>Bits</term>
 494   /// <term>Bits as binary number (argument for <see cref="GetSQL(Int32)"/> method)</term>
 495   /// </listheader>
 496   ///
 497   /// <item>
 498   /// <term><c>null</c></term>
 499   /// <term><c>null</c></term>
 500   /// <term><c>null</c></term>
 501   /// <term>000</term>
 502   /// <term>0</term>
 503   /// </item>
 504   ///
 505   /// <item>
 506   /// <term><c>null</c></term>
 507   /// <term><c>null</c></term>
 508   /// <term>not <c>null</c></term>
 509   /// <term>001</term>
 510   /// <term>1</term>
 511   /// </item>
 512   ///
 513   /// <item>
 514   /// <term><c>null</c></term>
 515   /// <term>not <c>null</c></term>
 516   /// <term><c>null</c></term>
 517   /// <term>010</term>
 518   /// <term>2</term>
 519   /// </item>
 520   ///
 521   /// <item>
 522   /// <term><c>null</c></term>
 523   /// <term>not <c>null</c></term>
 524   /// <term>not <c>null</c></term>
 525   /// <term>011</term>
 526   /// <term>3</term>
 527   /// </item>
 528   ///
 529   /// <item>
 530   /// <term>not <c>null</c></term>
 531   /// <term><c>null</c></term>
 532   /// <term><c>null</c></term>
 533   /// <term>100</term>
 534   /// <term>4</term>
 535   /// </item>
 536   ///
 537   /// <item>
 538   /// <term>not <c>null</c></term>
 539   /// <term><c>null</c></term>
 540   /// <term>not <c>null</c></term>
 541   /// <term>101</term>
 542   /// <term>5</term>
 543   /// </item>
 544   ///
 545   /// <item>
 546   /// <term>not <c>null</c></term>
 547   /// <term>not <c>null</c></term>
 548   /// <term><c>null</c></term>
 549   /// <term>110</term>
 550   /// <term>6</term>
 551   /// </item>
 552   ///
 553   /// <item>
 554   /// <term>not <c>null</c></term>
 555   /// <term>not <c>null</c></term>
 556   /// <term>not <c>null</c></term>
 557   /// <term>111</term>
 558   /// <term>7</term>
 559   /// </item>
 560   ///
 561   /// </list>
 562   /// A number with 3 bits can have 8 different values, so the permut
 563   /// </para>
 564   /// </remarks>
 565   public interface OrdinalSQLCache
 566   {
 567      /// <summary>
 568      /// Gets the SQL statement string based on permutation ordinal number calculated from which parameters to original
 569      /// See the remarks of this interface to learn more.
 570      /// </summary>
 571      /// <param name="permutationOrdinalNumber">The ordinal number of null parameter permutation sequence. See the rema
 572      /// <returns>Cached or created SQL string.</returns>
 573      String GetSQL( Int32 permutationOrdinalNumber );
 574   }
 575
 576   /// <summary>
 577   /// This interface is like <see cref="OrdinalSQLCache"/>, except it requires extra parameter of type <typeparamref na
 578   /// </summary>
 579   /// <typeparam name="T">The type of parameter for <see cref="GetSQL"/> method.</typeparam>
 580   /// <remarks>
 581   /// See remarks of <see cref="OrdinalSQLCache"/> to learn more about how permutation ordinal number is calculated.
 582   /// </remarks>
 583   public interface OrdinalSQLCache<in T>
 584   {
 585      /// <summary>
 586      /// Gets the SQL statement string based on permutation ordinal number calculated from which parameters to original
 587      /// See the remarks of <see cref="OrdinalSQLCache"/> to learn more.
 588      /// </summary>
 589      /// <param name="permutationOrdinalNumber">The ordinal number of null parameter permutation sequence. See the rema
 590      /// <param name="parameter">The custom parameter to be possibly used by factory.</param>
 591      /// <returns>Cached or created SQL string.</returns>
 592      String GetSQL( Int32 permutationOrdinalNumber, T parameter );
 593   }
 594
 595   /// <summary>
 596   /// Provides default implementation for <see cref="OrdinalSQLCache"/>, using array to cache SQL statements and custom
 597   /// </summary>
 598   public class DefaultOrdinalSQLCache : OrdinalSQLCache
 599   {
 600      private readonly String[] _cache;
 601      private readonly Func<Int32, String> _factory;
 602
 603      /// <summary>
 604      /// Creates a new instance of <see cref="DefaultOrdinalSQLCache"/> with given parameters.
 605      /// </summary>
 606      /// <param name="maxPermutationCount">The maximum amount of permutations.</param>
 607      /// <param name="factory">The callback to create new SQL statement from permutation ordinal number.</param>
 608      /// <exception cref="ArgumentNullException">If <paramref name="factory"/> is <c>null</c>.</exception>
 609      /// <exception cref="ArgumentException">If <paramref name="maxPermutationCount"/> is less than <c>0</c>.</exceptio
 610      public DefaultOrdinalSQLCache(
 611         Int32 maxPermutationCount,
 612         Func<Int32, String> factory
 613         )
 614      {
 615         this._cache = maxPermutationCount.NewArrayOfLength<String>( nameof( maxPermutationCount ) );
 616         this._factory = ArgumentValidator.ValidateNotNull( nameof( factory ), factory );
 617      }
 618
 619      /// <summary>
 620      /// Implements <see cref="OrdinalSQLCache.GetSQL"/> and returns possibly cached SQL statement string for given per
 621      /// If new SQL statement string is created, it is then cached.
 622      /// </summary>
 623      /// <param name="permutationOrdinalNumber">The permutation ordinal number.</param>
 624      /// <returns>Cached or created SQL statement string.</returns>
 625      public String GetSQL( Int32 permutationOrdinalNumber )
 626      {
 627         var retVal = this._cache[permutationOrdinalNumber];
 628         if ( retVal == null )
 629         {
 630            retVal = this._factory( permutationOrdinalNumber );
 631            if ( retVal != null )
 632            {
 633               Interlocked.Exchange( ref this._cache[permutationOrdinalNumber], retVal );
 634            }
 635         }
 636
 637         return retVal;
 638      }
 639   }
 640
 641   /// <summary>
 642   /// Provides default implementation for <see cref="OrdinalSQLCache{T}"/>, using array to cache SQL statements and cus
 643   /// </summary>
 644   /// <typeparam name="T"></typeparam>
 645   public class DefaultOrdinalSQLCache<T> : OrdinalSQLCache<T>
 646   {
 647      private readonly String[] _cache;
 648      private readonly Func<Int32, T, (String, Boolean)> _factory;
 649
 650      /// <summary>
 651      /// Creates a new instance of <see cref="DefaultOrdinalSQLCache{T}"/> with given parameters.
 652      /// </summary>
 653      /// <param name="maxPermutationCount">The maximum amount of permutations.</param>
 654      /// <param name="factory">The callback to create new SQL statement from permutation ordinal number and extra param
 655      /// <exception cref="ArgumentNullException">If <paramref name="factory"/> is <c>null</c>.</exception>
 656      /// <exception cref="ArgumentException">If <paramref name="maxPermutationCount"/> is less than <c>0</c>.</exceptio
 657      public DefaultOrdinalSQLCache(
 658         Int32 maxPermutationCount,
 659         Func<Int32, T, String> factory
 1660         ) : this( maxPermutationCount, factory == null ? (Func<Int32, T, (String, Boolean)>) null : ( n, p ) => (factor
 661      {
 1662      }
 663
 664      /// <summary>
 665      /// Creates a new instance of <see cref="DefaultOrdinalSQLCache{T}"/> with given parameters.
 666      /// </summary>
 667      /// <param name="maxPermutationCount">The maximum amount of permutations.</param>
 668      /// <param name="factory">The callback to create new SQL statement from permutation ordinal number and extra param
 669      /// <exception cref="ArgumentNullException">If <paramref name="factory"/> is <c>null</c>.</exception>
 670      /// <exception cref="ArgumentException">If <paramref name="maxPermutationCount"/> is less than <c>0</c>.</exceptio
 2671      public DefaultOrdinalSQLCache(
 2672         Int32 maxPermutationCount,
 2673         Func<Int32, T, (String, Boolean)> factory
 2674         )
 675      {
 2676         this._cache = maxPermutationCount.NewArrayOfLength<String>( nameof( maxPermutationCount ) );
 2677         this._factory = factory;
 2678      }
 679
 680      /// <summary>
 681      /// Implements <see cref="OrdinalSQLCache.GetSQL"/> and returns possibly cached SQL statement string for given per
 682      /// If new SQL statement string is created, and if factory method used to create it returns <c>true</c> in the res
 683      /// </summary>
 684      /// <param name="permutationOrderNumber">The permutation ordinal number.</param>
 685      /// <param name="param">The extra parameter to pass to factory method.</param>
 686      /// <returns>Cached or created SQL statement string.</returns>
 687      public String GetSQL( Int32 permutationOrderNumber, T param )
 688      {
 0689         var retVal = this._cache[permutationOrderNumber];
 0690         if ( retVal == null )
 691         {
 692            Boolean shouldCache;
 0693            (retVal, shouldCache) = this._factory( permutationOrderNumber, param );
 0694            if ( retVal != null && shouldCache )
 695            {
 0696               Interlocked.Exchange( ref this._cache[permutationOrderNumber], retVal );
 697            }
 698         }
 699
 0700         return retVal;
 701      }
 702   }
 703
 704   /// <summary>
 705   /// This class extends <see cref="DatabaseMetadataImpl"/> to implement lazy caching of SQL statement strings used to 
 706   /// </summary>
 707   public abstract class SQLCachingDatabaseMetadataImpl : DatabaseMetadataImpl
 708   {
 709
 710      private readonly DatabaseMetadataSQLCache _cache;
 711
 712      /// <summary>
 713      /// Inititalizes a new instance of <see cref="SQLCachingDatabaseMetadataImpl"/> with given parameters.
 714      /// </summary>
 715      /// <param name="vendorFunctionality">The <see cref="SQLConnectionVendorFunctionality"/> to use when creating <see
 716      /// <param name="name">The name of the database.</param>
 717      /// <param name="cache">The <see cref="DatabaseMetadataSQLCache"/> to use to retrieve SQL statement strings.</para
 718      /// <exception cref="ArgumentNullException">If either of <paramref name="vendorFunctionality"/> or <paramref name=
 719      public SQLCachingDatabaseMetadataImpl(
 720         SQLConnectionVendorFunctionality vendorFunctionality,
 721         String name,
 722         DatabaseMetadataSQLCache cache
 723         ) : base( vendorFunctionality, name )
 724      {
 725         this._cache = ArgumentValidator.ValidateNotNull( nameof( cache ), cache );
 726      }
 727
 728      /// <summary>
 729      /// This method implements <see cref="DatabaseMetadataImpl.CreateSQLForSchemaSearch"/> by using <see cref="Databas
 730      /// </summary>
 731      /// <param name="schemaNamePattern">The schema name pattern.</param>
 732      /// <returns>Created or cached SQL string for schema search.</returns>
 733      /// <remarks>
 734      /// The permutational ordinal number is computed using following logic:
 735      /// <list type="table">
 736      ///
 737      /// <listheader>
 738      /// <term>Value of <paramref name="schemaNamePattern"/></term>
 739      /// <term>Permutation ordinal number</term>
 740      /// </listheader>
 741      ///
 742      /// <item>
 743      /// <term><c>null</c></term>
 744      /// <term>0</term>
 745      /// </item>
 746      ///
 747      /// <item>
 748      /// <term>not <c>null</c></term>
 749      /// <term>1</term>
 750      /// </item>
 751      ///
 752      /// </list>
 753      /// </remarks>
 754      protected override String CreateSQLForSchemaSearch( String schemaNamePattern )
 755      {
 756         return this._cache.SchemaSearchCache.GetSQL( schemaNamePattern == null ? 0 : 1 );
 757      }
 758
 759      /// <summary>
 760      /// This method implements <see cref="DatabaseMetadataImpl.CreateSQLForTableSearch"/> by either using <see cref="D
 761      /// </summary>
 762      /// <param name="schemaNamePattern">The schema name pattern.</param>
 763      /// <param name="tableNamePattern">The table name pattern.</param>
 764      /// <param name="tableTypes">The table types.</param>
 765      /// <returns>Created or cached SQL string for table search.</returns>
 766      /// <remarks>
 767      /// The cache and permutational ordinal numbers are computed using following logic.
 768      /// <list type="table">
 769      ///
 770      /// <listheader>
 771      /// <term>Value of <paramref name="schemaNamePattern"/></term>
 772      /// <term>Value of <paramref name="tableNamePattern"/></term>
 773      /// <term>Value of <paramref name="tableTypes"/></term>
 774      /// <term>Permutation ordinal number</term>
 775      /// <term>Cache used</term>
 776      /// </listheader>
 777      ///
 778      /// <item>
 779      /// <term><c>null</c></term>
 780      /// <term><c>null</c></term>
 781      /// <term><c>null</c> or empty</term>
 782      /// <term>0</term>
 783      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 784      /// </item>
 785      ///
 786      /// <item>
 787      /// <term><c>null</c></term>
 788      /// <term><c>null</c></term>
 789      /// <term>has exactly one element</term>
 790      /// <term>1</term>
 791      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 792      /// </item>
 793      ///
 794      /// <item>
 795      /// <term><c>null</c></term>
 796      /// <term>not <c>null</c></term>
 797      /// <term><c>null</c> or empty</term>
 798      /// <term>2</term>
 799      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 800      /// </item>
 801      ///
 802      /// <item>
 803      /// <term><c>null</c></term>
 804      /// <term>not <c>null</c></term>
 805      /// <term>has exactly one element</term>
 806      /// <term>3</term>
 807      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 808      /// </item>
 809      ///
 810      /// <item>
 811      /// <term>not <c>null</c></term>
 812      /// <term><c>null</c></term>
 813      /// <term><c>null</c> or empty</term>
 814      /// <term>4</term>
 815      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 816      /// </item>
 817      ///
 818      /// <item>
 819      /// <term>not <c>null</c></term>
 820      /// <term><c>null</c></term>
 821      /// <term>has exactly one element</term>
 822      /// <term>5</term>
 823      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 824      /// </item>
 825      ///
 826      /// <item>
 827      /// <term>not <c>null</c></term>
 828      /// <term>not <c>null</c></term>
 829      /// <term><c>null</c> or empty</term>
 830      /// <term>6</term>
 831      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 832      /// </item>
 833      ///
 834      /// <item>
 835      /// <term>not <c>null</c></term>
 836      /// <term>not <c>null</c></term>
 837      /// <term>has exactly one element</term>
 838      /// <term>7</term>
 839      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCache"/></term>
 840      /// </item>
 841      ///
 842      /// <item>
 843      /// <term><c>null</c></term>
 844      /// <term><c>null</c></term>
 845      /// <term>has at least two elements</term>
 846      /// <term>0</term>
 847      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCacheForMultipleTableTypes"/></term>
 848      /// </item>
 849      ///
 850      /// <item>
 851      /// <term><c>null</c></term>
 852      /// <term>not <c>null</c></term>
 853      /// <term>has at least two elements</term>
 854      /// <term>1</term>
 855      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCacheForMultipleTableTypes"/></term>
 856      /// </item>
 857      ///
 858      /// <item>
 859      /// <term>not <c>null</c></term>
 860      /// <term><c>null</c></term>
 861      /// <term>has at least two elements</term>
 862      /// <term>2</term>
 863      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCacheForMultipleTableTypes"/></term>
 864      /// </item>
 865      ///
 866      /// <item>
 867      /// <term>not <c>null</c></term>
 868      /// <term>not <c>null</c></term>
 869      /// <term>has at least two elements</term>
 870      /// <term>3</term>
 871      /// <term><see cref="DatabaseMetadataSQLCache.TableSearchCacheForMultipleTableTypes"/></term>
 872      /// </item>
 873      ///
 874      /// </list>
 875      /// </remarks>
 876      protected override String CreateSQLForTableSearch( String schemaNamePattern, String tableNamePattern, TableType[] 
 877      {
 878         var noTypes = tableTypes.IsNullOrEmpty();
 879         String retVal;
 880         if ( noTypes || tableTypes.Length == 1 )
 881         {
 882            // 0..1 table types
 883            retVal = this._cache.TableSearchCache.GetSQL( GetLexicographicalOrderNumber( schemaNamePattern, tableNamePat
 884         }
 885         else
 886         {
 887            // 2..* table types
 888            retVal = this._cache.TableSearchCacheForMultipleTableTypes.GetSQL( GetLexicographicalOrderNumber( schemaName
 889         }
 890         return retVal;
 891      }
 892
 893      /// <summary>
 894      /// This method implements <see cref="DatabaseMetadataImpl.CreateSQLForColumnSearch"/> by using <see cref="Databas
 895      /// </summary>
 896      /// <param name="schemaNamePattern">The schema name pattern.</param>
 897      /// <param name="tableNamePattern">The table name pattern.</param>
 898      /// <param name="columnNamePattern">The column name pattern.</param>
 899      /// <returns>Created or cached SQL string for column search.</returns>
 900      /// <remarks>
 901      /// The permutational ordinal number is computed using following logic:
 902      /// <list type="table">
 903      ///
 904      /// <listheader>
 905      /// <term>Value of <paramref name="schemaNamePattern"/></term>
 906      /// <term>Value of <paramref name="tableNamePattern"/></term>
 907      /// <term>Value of <paramref name="columnNamePattern"/></term>
 908      /// <term>Permutation ordinal number</term>
 909      /// </listheader>
 910      ///
 911      /// <item>
 912      /// <term><c>null</c></term>
 913      /// <term><c>null</c></term>
 914      /// <term><c>null</c></term>
 915      /// <term>0</term>
 916      /// </item>
 917      ///
 918      /// <item>
 919      /// <term><c>null</c></term>
 920      /// <term><c>null</c></term>
 921      /// <term>not <c>null</c></term>
 922      /// <term>1</term>
 923      /// </item>
 924      ///
 925      /// <item>
 926      /// <term><c>null</c></term>
 927      /// <term>not <c>null</c></term>
 928      /// <term><c>null</c></term>
 929      /// <term>2</term>
 930      /// </item>
 931      ///
 932      /// <item>
 933      /// <term><c>null</c></term>
 934      /// <term>not <c>null</c></term>
 935      /// <term>not <c>null</c></term>
 936      /// <term>3</term>
 937      /// </item>
 938      ///
 939      /// <item>
 940      /// <term>not <c>null</c></term>
 941      /// <term><c>null</c></term>
 942      /// <term><c>null</c></term>
 943      /// <term>4</term>
 944      /// </item>
 945      ///
 946      /// <item>
 947      /// <term>not <c>null</c></term>
 948      /// <term><c>null</c></term>
 949      /// <term>not <c>null</c></term>
 950      /// <term>5</term>
 951      /// </item>
 952      ///
 953      /// <item>
 954      /// <term>not <c>null</c></term>
 955      /// <term>not <c>null</c></term>
 956      /// <term><c>null</c></term>
 957      /// <term>6</term>
 958      /// </item>
 959      ///
 960      /// <item>
 961      /// <term>not <c>null</c></term>
 962      /// <term>not <c>null</c></term>
 963      /// <term>not <c>null</c></term>
 964      /// <term>7</term>
 965      /// </item>
 966      ///
 967      /// </list>
 968      /// </remarks>
 969      protected override String CreateSQLForColumnSearch( String schemaNamePattern, String tableNamePattern, String colu
 970      {
 971         return this._cache.ColumnSearchCache.GetSQL( GetLexicographicalOrderNumber( schemaNamePattern, tableNamePattern
 972      }
 973
 974      /// <summary>
 975      /// This method implements <see cref="DatabaseMetadataImpl.CreateSQLForPrimaryKeySearch"/> by using <see cref="Dat
 976      /// </summary>
 977      /// <param name="schemaNamePattern">The schema name pattern.</param>
 978      /// <param name="tableNamePattern">The table name pattern.</param>
 979      /// <returns>Created or cached SQL string for primary key search.</returns>
 980      /// <remarks>
 981      /// The permutational ordinal number is computed using following logic:
 982      /// <list type="table">
 983      ///
 984      /// <listheader>
 985      /// <term>Value of <paramref name="schemaNamePattern"/></term>
 986      /// <term>Value of <paramref name="tableNamePattern"/></term>
 987      /// <term>Permutation ordinal number</term>
 988      /// </listheader>
 989      ///
 990      /// <item>
 991      /// <term><c>null</c></term>
 992      /// <term><c>null</c></term>
 993      /// <term>0</term>
 994      /// </item>
 995      ///
 996      /// <item>
 997      /// <term><c>null</c></term>
 998      /// <term>not <c>null</c></term>
 999      /// <term>1</term>
 1000      /// </item>
 1001      ///
 1002      /// <item>
 1003      /// <term>not <c>null</c></term>
 1004      /// <term><c>null</c></term>
 1005      /// <term>2</term>
 1006      /// </item>
 1007      ///
 1008      /// <item>
 1009      /// <term>not <c>null</c></term>
 1010      /// <term>not <c>null</c></term>
 1011      /// <term>3</term>
 1012      /// </item>
 1013      ///
 1014      /// </list>
 1015      /// </remarks>
 1016      protected override String CreateSQLForPrimaryKeySearch( String schemaNamePattern, String tableNamePattern )
 1017      {
 1018         return this._cache.PrimaryKeySearchCache.GetSQL( GetLexicographicalOrderNumber( schemaNamePattern, tableNamePat
 1019      }
 1020
 1021      /// <summary>
 1022      /// This method implements <see cref="DatabaseMetadataImpl.CreateSQLForForeignKeySearch"/> by using <see cref="Dat
 1023      /// </summary>
 1024      /// <param name="primarySchemaName">The name pattern for schema name of the table with primary key.</param>
 1025      /// <param name="primaryTableName">The name pattern for table name of the table with primary key.</param>
 1026      /// <param name="foreignSchemaName">The name pattern for schema name of the table with foreeign key.</param>
 1027      /// <param name="foreignTableName">The name pattern for table name of the table with foreeign key.</param>
 1028      /// <returns>Created or cached SQL string for primary key search.</returns>
 1029      /// <remarks>
 1030      /// The permutational ordinal number is computed using following logic:
 1031      /// <list type="table">
 1032      ///
 1033      /// <listheader>
 1034      /// <term>Value of <paramref name="primarySchemaName"/></term>
 1035      /// <term>Value of <paramref name="primaryTableName"/></term>
 1036      /// <term>Value of <paramref name="foreignSchemaName"/></term>
 1037      /// <term>Value of <paramref name="foreignTableName"/></term>
 1038      /// <term>Permutation ordinal number</term>
 1039      /// </listheader>
 1040      ///
 1041      /// <item>
 1042      /// <term><c>null</c></term>
 1043      /// <term><c>null</c></term>
 1044      /// <term><c>null</c></term>
 1045      /// <term><c>null</c></term>
 1046      /// <term>0</term>
 1047      /// </item>
 1048      ///
 1049      /// <item>
 1050      /// <term><c>null</c></term>
 1051      /// <term><c>null</c></term>
 1052      /// <term><c>null</c></term>
 1053      /// <term>not <c>null</c></term>
 1054      /// <term>1</term>
 1055      /// </item>
 1056      ///
 1057      /// <item>
 1058      /// <term><c>null</c></term>
 1059      /// <term><c>null</c></term>
 1060      /// <term>not <c>null</c></term>
 1061      /// <term><c>null</c></term>
 1062      /// <term>2</term>
 1063      /// </item>
 1064      ///
 1065      /// <item>
 1066      /// <term><c>null</c></term>
 1067      /// <term><c>null</c></term>
 1068      /// <term>not <c>null</c></term>
 1069      /// <term>not <c>null</c></term>
 1070      /// <term>3</term>
 1071      /// </item>
 1072      ///
 1073      /// <item>
 1074      /// <term><c>null</c></term>
 1075      /// <term>not <c>null</c></term>
 1076      /// <term><c>null</c></term>
 1077      /// <term><c>null</c></term>
 1078      /// <term>4</term>
 1079      /// </item>
 1080      ///
 1081      /// <item>
 1082      /// <term><c>null</c></term>
 1083      /// <term>not <c>null</c></term>
 1084      /// <term><c>null</c></term>
 1085      /// <term>not <c>null</c></term>
 1086      /// <term>5</term>
 1087      /// </item>
 1088      ///
 1089      /// <item>
 1090      /// <term><c>null</c></term>
 1091      /// <term>not <c>null</c></term>
 1092      /// <term>not <c>null</c></term>
 1093      /// <term><c>null</c></term>
 1094      /// <term>6</term>
 1095      /// </item>
 1096      ///
 1097      /// <item>
 1098      /// <term><c>null</c></term>
 1099      /// <term>not <c>null</c></term>
 1100      /// <term>not <c>null</c></term>
 1101      /// <term>not <c>null</c></term>
 1102      /// <term>7</term>
 1103      /// </item>
 1104      ///
 1105      /// <item>
 1106      /// <term>not <c>null</c></term>
 1107      /// <term><c>null</c></term>
 1108      /// <term><c>null</c></term>
 1109      /// <term><c>null</c></term>
 1110      /// <term>8</term>
 1111      /// </item>
 1112      ///
 1113      /// <item>
 1114      /// <term>not <c>null</c></term>
 1115      /// <term><c>null</c></term>
 1116      /// <term><c>null</c></term>
 1117      /// <term>not <c>null</c></term>
 1118      /// <term>9</term>
 1119      /// </item>
 1120      ///
 1121      /// <item>
 1122      /// <term>not <c>null</c></term>
 1123      /// <term><c>null</c></term>
 1124      /// <term>not <c>null</c></term>
 1125      /// <term><c>null</c></term>
 1126      /// <term>10</term>
 1127      /// </item>
 1128      ///
 1129      /// <item>
 1130      /// <term>not <c>null</c></term>
 1131      /// <term><c>null</c></term>
 1132      /// <term>not <c>null</c></term>
 1133      /// <term>not <c>null</c></term>
 1134      /// <term>11</term>
 1135      /// </item>
 1136      ///
 1137      /// <item>
 1138      /// <term>not <c>null</c></term>
 1139      /// <term>not <c>null</c></term>
 1140      /// <term><c>null</c></term>
 1141      /// <term><c>null</c></term>
 1142      /// <term>12</term>
 1143      /// </item>
 1144      ///
 1145      /// <item>
 1146      /// <term>not <c>null</c></term>
 1147      /// <term>not <c>null</c></term>
 1148      /// <term><c>null</c></term>
 1149      /// <term>not <c>null</c></term>
 1150      /// <term>13</term>
 1151      /// </item>
 1152      ///
 1153      /// <item>
 1154      /// <term>not <c>null</c></term>
 1155      /// <term>not <c>null</c></term>
 1156      /// <term>not <c>null</c></term>
 1157      /// <term><c>null</c></term>
 1158      /// <term>14</term>
 1159      /// </item>
 1160      ///
 1161      /// <item>
 1162      /// <term>not <c>null</c></term>
 1163      /// <term><c>null</c></term>
 1164      /// <term><c>null</c></term>
 1165      /// <term>not <c>null</c></term>
 1166      /// <term>15</term>
 1167      /// </item>
 1168      ///
 1169      /// </list>
 1170      /// </remarks>
 1171      protected override String CreateSQLForForeignKeySearch( String primarySchemaName, String primaryTableName, String 
 1172      {
 1173         return this._cache.ForeignKeySearchCache.GetSQL( GetLexicographicalOrderNumber( primarySchemaName, primaryTable
 1174      }
 1175
 1176      private static Int32 GetLexicographicalOrderNumber( String p1, String p2 )
 1177      {
 1178         var retVal = p2 == null ? 0 : 1;
 1179         if ( p1 != null )
 1180         {
 1181            retVal += 2;
 1182         }
 1183         return retVal;
 1184      }
 1185
 1186      private static Int32 GetLexicographicalOrderNumber( String p1, String p2, String p3 )
 1187      {
 1188         // Consider boolean array as array of characters '0' or '1'.
 1189         // So with the array of 3 booleans, we would get
 1190         // 000 -> 0
 1191         // 001 -> 1
 1192         // 010 -> 2
 1193         // 011 -> 3
 1194         // 100 -> 4
 1195         // 101 -> 5
 1196         // 110 -> 6
 1197         // 111 -> 7
 1198
 1199         // So basically, we need to perform number base conversion from 2 to 10 using boolean array
 1200         // Our boolean array is paramz.Select(p => p != null) which we can inline
 1201         // Unwrap this generic method for variations taking 2,3, and 4 strings, to avoid creating array for "params" pa
 1202         //var retVal = 0;
 1203         //var curPow = 1;
 1204         //for ( var i = 0; i < paramz.Length; ++i )
 1205         //{
 1206         //   if ( paramz[i] != null )
 1207         //   {
 1208         //      retVal += curPow;
 1209         //   }
 1210         //   curPow *= 2;
 1211         //}
 1212
 1213         //return retVal;
 1214
 1215         var retVal = p3 == null ? 0 : 1;
 1216         if ( p2 != null )
 1217         {
 1218            retVal += 2;
 1219         }
 1220         if ( p1 != null )
 1221         {
 1222            retVal += 4;
 1223         }
 1224
 1225         return retVal;
 1226      }
 1227
 1228
 1229      private static Int32 GetLexicographicalOrderNumber( String p1, String p2, String p3, String p4 )
 1230      {
 1231         var retVal = p4 == null ? 0 : 1;
 1232         if ( p3 != null )
 1233         {
 1234            retVal += 2;
 1235         }
 1236         if ( p2 != null )
 1237         {
 1238            retVal += 4;
 1239         }
 1240         if ( p1 != null )
 1241         {
 1242            retVal += 8;
 1243         }
 1244
 1245         return retVal;
 1246      }
 1247
 1248   }
 1249}