System.Data.SQLite
Check-in [3e1da60858]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Allow virtual tables implemented in managed code to implement functions.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 3e1da60858edc922f4d69435e2eefa3680c5f0e0
User & Date: mistachkin 2013-07-01 10:16:18
Context
2013-07-01
18:22
In the SQLiteFunction class, check if the database connection is open prior to attempting to call the Cancel method. Add NoFunctions connection flag to skip binding functions registered in the application domain. Fixes and adjustments to comments. Add several data-types for compatibility purposes. Fix for [fe50b8c2e8]. check-in: dff9a878dd user: mistachkin tags: trunk
10:16
Allow virtual tables implemented in managed code to implement functions. check-in: 3e1da60858 user: mistachkin tags: trunk
2013-06-28
06:47
When reading a DateTime value, avoid unnecessary string conversions. Fix for [4d87fbc742]. check-in: e1b4194a30 user: mistachkin tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to System.Data.SQLite/SQLite3.cs.

  1731   1731       {
  1732   1732         return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1);
  1733   1733       }
  1734   1734   
  1735   1735   #if INTEROP_VIRTUAL_TABLE
  1736   1736       /// <summary>
  1737   1737       /// Calls the native SQLite core library in order to declare a virtual table
  1738         -    /// in response to a call into the xCreate or xConnect virtual table methods.
         1738  +    /// in response to a call into the <see cref="ISQLiteNativeModule.xCreate" />
         1739  +    /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods.
  1739   1740       /// </summary>
  1740   1741       /// <param name="module">
  1741   1742       /// The virtual table module that is to be responsible for the virtual table
  1742   1743       /// being declared.
  1743   1744       /// </param>
  1744   1745       /// <param name="strSql">
  1745   1746       /// The string containing the SQL statement describing the virtual table to
................................................................................
  1785   1786               if (pSql != IntPtr.Zero)
  1786   1787               {
  1787   1788                   SQLiteMemory.Free(pSql);
  1788   1789                   pSql = IntPtr.Zero;
  1789   1790               }
  1790   1791           }
  1791   1792       }
         1793  +
         1794  +    /// <summary>
         1795  +    /// Calls the native SQLite core library in order to declare a virtual table
         1796  +    /// function in response to a call into the <see cref="ISQLiteNativeModule.xCreate" />
         1797  +    /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods.
         1798  +    /// </summary>
         1799  +    /// <param name="module">
         1800  +    /// The virtual table module that is to be responsible for the virtual table
         1801  +    /// function being declared.
         1802  +    /// </param>
         1803  +    /// <param name="argumentCount">
         1804  +    /// The number of arguments to the function being declared.
         1805  +    /// </param>
         1806  +    /// <param name="name">
         1807  +    /// The name of the function being declared.
         1808  +    /// </param>
         1809  +    /// <param name="error">
         1810  +    /// Upon success, the contents of this parameter are undefined.  Upon failure,
         1811  +    /// it should contain an appropriate error message.
         1812  +    /// </param>
         1813  +    /// <returns>
         1814  +    /// A standard SQLite return code.
         1815  +    /// </returns>
         1816  +    internal override SQLiteErrorCode DeclareVirtualFunction(
         1817  +        SQLiteModule module,
         1818  +        int argumentCount,
         1819  +        string name,
         1820  +        ref string error
         1821  +        )
         1822  +    {
         1823  +        if (_sql == null)
         1824  +        {
         1825  +            error = "connection has an invalid handle";
         1826  +            return SQLiteErrorCode.Error;
         1827  +        }
         1828  +
         1829  +        IntPtr pName = IntPtr.Zero;
         1830  +
         1831  +        try
         1832  +        {
         1833  +            pName = SQLiteString.Utf8IntPtrFromString(name);
         1834  +
         1835  +            SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_overload_function(
         1836  +                _sql, pName, argumentCount);
         1837  +
         1838  +            if (n != SQLiteErrorCode.Ok) error = GetLastError();
         1839  +
         1840  +            return n;
         1841  +        }
         1842  +        finally
         1843  +        {
         1844  +            if (pName != IntPtr.Zero)
         1845  +            {
         1846  +                SQLiteMemory.Free(pName);
         1847  +                pName = IntPtr.Zero;
         1848  +            }
         1849  +        }
         1850  +    }
  1792   1851   #endif
  1793   1852   
  1794   1853       /// <summary>
  1795   1854       /// Enables or disabled extension loading by SQLite.
  1796   1855       /// </summary>
  1797   1856       /// <param name="bOnOff">
  1798   1857       /// True to enable loading of extensions, false to disable.

Changes to System.Data.SQLite/SQLiteBase.cs.

   233    233       /// The module object previously passed to the <see cref="CreateModule" />
   234    234       /// method.
   235    235       /// </param>
   236    236       internal abstract void DisposeModule(SQLiteModule module);
   237    237   
   238    238       /// <summary>
   239    239       /// Calls the native SQLite core library in order to declare a virtual table
   240         -    /// in response to a call into the xCreate or xConnect virtual table methods.
          240  +    /// in response to a call into the <see cref="ISQLiteNativeModule.xCreate" />
          241  +    /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods.
   241    242       /// </summary>
   242    243       /// <param name="module">
   243    244       /// The virtual table module that is to be responsible for the virtual table
   244    245       /// being declared.
   245    246       /// </param>
   246    247       /// <param name="strSql">
   247    248       /// The string containing the SQL statement describing the virtual table to
................................................................................
   251    252       /// Upon success, the contents of this parameter are undefined.  Upon failure,
   252    253       /// it should contain an appropriate error message.
   253    254       /// </param>
   254    255       /// <returns>
   255    256       /// A standard SQLite return code.
   256    257       /// </returns>
   257    258       internal abstract SQLiteErrorCode DeclareVirtualTable(SQLiteModule module, string strSql, ref string error);
          259  +
          260  +    /// <summary>
          261  +    /// Calls the native SQLite core library in order to declare a virtual table
          262  +    /// function in response to a call into the <see cref="ISQLiteNativeModule.xCreate" />
          263  +    /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods.
          264  +    /// </summary>
          265  +    /// <param name="module">
          266  +    /// The virtual table module that is to be responsible for the virtual table
          267  +    /// function being declared.
          268  +    /// </param>
          269  +    /// <param name="argumentCount">
          270  +    /// The number of arguments to the function being declared.
          271  +    /// </param>
          272  +    /// <param name="name">
          273  +    /// The name of the function being declared.
          274  +    /// </param>
          275  +    /// <param name="error">
          276  +    /// Upon success, the contents of this parameter are undefined.  Upon failure,
          277  +    /// it should contain an appropriate error message.
          278  +    /// </param>
          279  +    /// <returns>
          280  +    /// A standard SQLite return code.
          281  +    /// </returns>
          282  +    internal abstract SQLiteErrorCode DeclareVirtualFunction(SQLiteModule module, int argumentCount, string name, ref string error);
   258    283   #endif
   259    284   
   260    285       /// <summary>
   261    286       /// Enables or disabled extension loading by SQLite.
   262    287       /// </summary>
   263    288       /// <param name="bOnOff">
   264    289       /// True to enable loading of extensions, false to disable.

Changes to System.Data.SQLite/SQLiteFunction.cs.

    86     86       /// <summary>
    87     87       /// Internal constructor, initializes the function's internal variables.
    88     88       /// </summary>
    89     89       protected SQLiteFunction()
    90     90       {
    91     91         _contextDataList = new Dictionary<IntPtr, AggregateData>();
    92     92       }
           93  +
           94  +    /// <summary>
           95  +    /// Constructs an instance of this class using the specified data-type
           96  +    /// conversion parameters.
           97  +    /// </summary>
           98  +    /// <param name="format">
           99  +    /// The DateTime format to be used when converting string values to a
          100  +    /// DateTime and binding DateTime parameters.
          101  +    /// </param>
          102  +    /// <param name="kind">
          103  +    /// The <see cref="DateTimeKind" /> to be used when creating DateTime
          104  +    /// values.
          105  +    /// </param>
          106  +    /// <param name="formatString">
          107  +    /// The format string to be used when parsing and formatting DateTime
          108  +    /// values.
          109  +    /// </param>
          110  +    /// <param name="utf16">
          111  +    /// Non-zero to create a UTF-16 data-type conversion context; otherwise,
          112  +    /// a UTF-8 data-type conversion context will be created.
          113  +    /// </param>
          114  +    protected SQLiteFunction(
          115  +        SQLiteDateFormats format,
          116  +        DateTimeKind kind,
          117  +        string formatString,
          118  +        bool utf16
          119  +        )
          120  +        : this()
          121  +    {
          122  +        if (utf16)
          123  +            _base = new SQLite3_UTF16(format, kind, formatString, IntPtr.Zero, null, false);
          124  +        else
          125  +            _base = new SQLite3(format, kind, formatString, IntPtr.Zero, null, false);
          126  +    }
    93    127   
    94    128       ///////////////////////////////////////////////////////////////////////////////////////////////
    95    129   
    96    130       #region IDisposable Members
    97    131       /// <summary>
    98    132       /// Disposes of any active contextData variables that were not automatically cleaned up.  Sometimes this can happen if
    99    133       /// someone closes the connection while a DataReader is open.

Changes to System.Data.SQLite/SQLiteModule.cs.

  5174   5174           /// <summary>
  5175   5175           /// This field is used to store the virtual table cursor instances
  5176   5176           /// associated with this module.  The native pointer to the
  5177   5177           /// sqlite3_vtab_cursor derived structure is used to key into this
  5178   5178           /// collection.
  5179   5179           /// </summary>
  5180   5180           private Dictionary<IntPtr, SQLiteVirtualTableCursor> cursors;
         5181  +
         5182  +        ///////////////////////////////////////////////////////////////////////
         5183  +
         5184  +        /// <summary>
         5185  +        /// This field is used to store the virtual table function instances
         5186  +        /// associated with this module.  The case-insensitive function name
         5187  +        /// and the number of arguments (with -1 meaning "any") are used to
         5188  +        /// construct the string that is used to key into this collection.
         5189  +        /// </summary>
         5190  +        private Dictionary<string, SQLiteFunction> functions;
  5181   5191           #endregion
  5182   5192   
  5183   5193           ///////////////////////////////////////////////////////////////////////
  5184   5194   
  5185   5195           #region Public Constructors
  5186   5196           /// <summary>
  5187   5197           /// Constructs an instance of this class.
................................................................................
  5193   5203           {
  5194   5204               if (name == null)
  5195   5205                   throw new ArgumentNullException("name");
  5196   5206   
  5197   5207               this.name = name;
  5198   5208               this.tables = new Dictionary<IntPtr, SQLiteVirtualTable>();
  5199   5209               this.cursors = new Dictionary<IntPtr, SQLiteVirtualTableCursor>();
         5210  +            this.functions = new Dictionary<string, SQLiteFunction>();
  5200   5211           }
  5201   5212           #endregion
  5202   5213   
  5203   5214           ///////////////////////////////////////////////////////////////////////
  5204   5215   
  5205   5216           #region Internal Methods
  5206   5217           /// <summary>
................................................................................
  5785   5796   
  5786   5797               return pCursor;
  5787   5798           }
  5788   5799           #endregion
  5789   5800   
  5790   5801           ///////////////////////////////////////////////////////////////////////
  5791   5802   
         5803  +        #region Function Lookup Methods
         5804  +        /// <summary>
         5805  +        /// Deterimines the key that should be used to identify and store the
         5806  +        /// function instance for the virtual table (i.e. to be returned via
         5807  +        /// the <see cref="ISQLiteNativeModule.xFindFunction" /> method).
         5808  +        /// </summary>
         5809  +        /// <param name="argumentCount">
         5810  +        /// The number of arguments to the virtual table function.
         5811  +        /// </param>
         5812  +        /// <param name="name">
         5813  +        /// The name of the virtual table function.
         5814  +        /// </param>
         5815  +        /// <param name="function">
         5816  +        /// The <see cref="SQLiteFunction" /> object instance associated with
         5817  +        /// this virtual table function.
         5818  +        /// </param>
         5819  +        /// <returns>
         5820  +        /// The string that should be used to identify and store the virtual
         5821  +        /// table function instance.  This method cannot return null.  If null
         5822  +        /// is returned from this method, the behavior is undefined.
         5823  +        /// </returns>
         5824  +        protected virtual string GetFunctionKey(
         5825  +            int argumentCount,
         5826  +            string name,
         5827  +            SQLiteFunction function
         5828  +            )
         5829  +        {
         5830  +            return String.Format("{0}:{1}", argumentCount, name);
         5831  +        }
         5832  +        #endregion
         5833  +
         5834  +        ///////////////////////////////////////////////////////////////////////
         5835  +
  5792   5836           #region Table Declaration Helper Methods
  5793   5837           /// <summary>
  5794   5838           /// Attempts to declare the schema for the virtual table using the
  5795   5839           /// specified database connection.
  5796   5840           /// </summary>
  5797   5841           /// <param name="connection">
  5798   5842           /// The <see cref="SQLiteConnection" /> object instance to use when
................................................................................
  5828   5872                   error = "connection has invalid handle";
  5829   5873                   return SQLiteErrorCode.Error;
  5830   5874               }
  5831   5875   
  5832   5876               return sqliteBase.DeclareVirtualTable(this, sql, ref error);
  5833   5877           }
  5834   5878           #endregion
         5879  +
         5880  +        ///////////////////////////////////////////////////////////////////////
         5881  +
         5882  +        #region Function Declaration Helper Methods
         5883  +        protected virtual SQLiteErrorCode DeclareFunction(
         5884  +            SQLiteConnection connection,
         5885  +            int argumentCount,
         5886  +            string name,
         5887  +            ref string error
         5888  +            )
         5889  +        {
         5890  +            if (connection == null)
         5891  +            {
         5892  +                error = "invalid connection";
         5893  +                return SQLiteErrorCode.Error;
         5894  +            }
         5895  +
         5896  +            SQLiteBase sqliteBase = connection._sql;
         5897  +
         5898  +            if (sqliteBase == null)
         5899  +            {
         5900  +                error = "connection has invalid handle";
         5901  +                return SQLiteErrorCode.Error;
         5902  +            }
         5903  +
         5904  +            return sqliteBase.DeclareVirtualFunction(
         5905  +                this, argumentCount, name, ref error);
         5906  +        }
         5907  +        #endregion
  5835   5908   
  5836   5909           ///////////////////////////////////////////////////////////////////////
  5837   5910   
  5838   5911           #region Error Handling Helper Methods
  5839   5912           /// <summary>
  5840   5913           /// Arranges for the specified error message to be placed into the
  5841   5914           /// zErrMsg field of a sqlite3_vtab derived structure, freeing the
................................................................................
  7036   7109           {
  7037   7110               try
  7038   7111               {
  7039   7112                   SQLiteVirtualTable table = TableFromIntPtr(pVtab);
  7040   7113   
  7041   7114                   if (table != null)
  7042   7115                   {
         7116  +                    string name = SQLiteString.StringFromUtf8IntPtr(zName);
  7043   7117                       SQLiteFunction function = null;
  7044   7118   
  7045   7119                       if (FindFunction(
  7046         -                            table, nArg,
  7047         -                            SQLiteString.StringFromUtf8IntPtr(zName),
  7048         -                            ref function, ref pClientData))
         7120  +                            table, nArg, name, ref function, ref pClientData))
  7049   7121                       {
  7050   7122                           if (function != null)
  7051   7123                           {
         7124  +                            string key = GetFunctionKey(nArg, name, function);
         7125  +
         7126  +                            functions[key] = function;
  7052   7127                               callback = function.ScalarCallback;
         7128  +
  7053   7129                               return 1;
  7054   7130                           }
  7055   7131                           else
  7056   7132                           {
  7057   7133                               SetTableError(pVtab, "no function was created");
  7058   7134                           }
  7059   7135                       }
................................................................................
  7790   7866           /// <see cref="Dispose()" /> method.  Zero if this method is being
  7791   7867           /// called from the finalizer.
  7792   7868           /// </param>
  7793   7869           protected virtual void Dispose(bool disposing)
  7794   7870           {
  7795   7871               if (!disposed)
  7796   7872               {
  7797         -                //if (disposing)
  7798         -                //{
  7799         -                //    ////////////////////////////////////
  7800         -                //    // dispose managed resources here...
  7801         -                //    ////////////////////////////////////
  7802         -                //}
         7873  +                if (disposing)
         7874  +                {
         7875  +                    ////////////////////////////////////
         7876  +                    // dispose managed resources here...
         7877  +                    ////////////////////////////////////
         7878  +
         7879  +                    if (functions != null)
         7880  +                        functions.Clear();
         7881  +                }
  7803   7882   
  7804   7883                   //////////////////////////////////////
  7805   7884                   // release unmanaged resources here...
  7806   7885                   //////////////////////////////////////
  7807   7886   
  7808   7887                   try
  7809   7888                   {

Changes to System.Data.SQLite/UnsafeNativeMethods.cs.

   986    986       [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
   987    987   #else
   988    988       [DllImport(SQLITE_DLL)]
   989    989   #endif
   990    990       internal static extern SQLiteErrorCode sqlite3_load_extension(
   991    991           IntPtr db, byte[] fileName, byte[] procName, ref IntPtr pError);
   992    992   
          993  +#if !PLATFORM_COMPACTFRAMEWORK
          994  +    [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)]
          995  +#else
          996  +    [DllImport(SQLITE_DLL)]
          997  +#endif
          998  +    internal static extern SQLiteErrorCode sqlite3_overload_function(IntPtr db, IntPtr zName, int nArgs);
          999  +
   993   1000   #if !PLATFORM_COMPACTFRAMEWORK
   994   1001       [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)]
   995   1002   #else
   996   1003       [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)]
   997   1004   #endif
   998   1005       internal static extern SQLiteErrorCode sqlite3_win32_set_directory(uint type, string value);
   999   1006   

Changes to Tests/vtab.eagle.

    16     16   ###############################################################################
    17     17   
    18     18   package require System.Data.SQLite.Test
    19     19   runSQLiteTestPrologue
    20     20   
    21     21   ###############################################################################
    22     22   
    23         -runTest {test vtab-1.1 {virtual table support} -setup {
           23  +runTest {test vtab-1.1 {basic virtual table support} -setup {
    24     24     setupDb [set fileName vtab-1.1.db]
    25     25   } -body {
    26     26     set id [object invoke Interpreter.GetActive NextId]
    27     27     set dataSource [file join [getDatabaseDirectory] $fileName]
    28     28   
    29     29     set sql { \
    30     30       CREATE VIRTUAL TABLE t${id} USING mod${id}; \
................................................................................
   316    316     unset -nocomplain result code results errors sql dataSource id db fileName
   317    317   } -constraints \
   318    318   {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
   319    319   defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
   320    320   [string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
   321    321   \{\} 0 \{1 2 3 4 5 Error \{SQL logic error or missing database
   322    322   virtual table "t\d+" is read-only\}\}$}]}
          323  +
          324  +###############################################################################
          325  +
          326  +runTest {test vtab-1.4 {virtual table function support} -setup {
          327  +  setupDb [set fileName vtab-1.4.db]
          328  +} -body {
          329  +  set id [object invoke Interpreter.GetActive NextId]
          330  +  set dataSource [file join [getDatabaseDirectory] $fileName]
          331  +
          332  +  set sql(1) { \
          333  +    CREATE VIRTUAL TABLE t${id} USING mod${id}; \
          334  +  }
          335  +
          336  +  set sql(2) { \
          337  +    SELECT Base64(x, CAST('one' AS BLOB)) FROM t${id}; \
          338  +  }
          339  +
          340  +  set sql(3) { \
          341  +    SELECT Base64(x, CAST('one' AS BLOB), 'two') FROM t${id}; \
          342  +  }
          343  +
          344  +  set sql(4) { \
          345  +    SELECT Base65(x, CAST('one' AS BLOB)) FROM t${id}; \
          346  +  }
          347  +
          348  +  unset -nocomplain results errors
          349  +
          350  +  set code [compileCSharpWith [subst {
          351  +    using System;
          352  +    using System.Data.SQLite;
          353  +    using Eagle._Containers.Public;
          354  +
          355  +    namespace _Dynamic${id}
          356  +    {
          357  +      public class SQLiteFunction${id} : SQLiteFunction
          358  +      {
          359  +        public SQLiteFunction${id}()
          360  +          : base(SQLiteDateFormats.Default, DateTimeKind.Unspecified,
          361  +                 null, false)
          362  +        {
          363  +          // do nothing.
          364  +        }
          365  +
          366  +        ///////////////////////////////////////////////////////////////////////
          367  +
          368  +        public override object Invoke(
          369  +          object\[\] args
          370  +          )
          371  +        {
          372  +          if (args == null)
          373  +            return null;
          374  +
          375  +          if (args.Length != 2)
          376  +            return new ArgumentException(String.Format(
          377  +              "need exactly two arguments, got {0}", args.Length));
          378  +
          379  +          object arg = args\[1\];
          380  +
          381  +          if (arg == null)
          382  +            return String.Empty;
          383  +
          384  +          Type type = arg.GetType();
          385  +
          386  +          if (type == typeof(DBNull))
          387  +            return String.Empty;
          388  +
          389  +          if (type != typeof(byte\[\]))
          390  +            return new ArgumentException(String.Format(
          391  +              "argument must be byte array, got {0}", type));
          392  +
          393  +          return Convert.ToBase64String((byte\[\]) arg);
          394  +        }
          395  +      }
          396  +
          397  +      /////////////////////////////////////////////////////////////////////////
          398  +
          399  +      public sealed class SQLiteModuleTest${id} : SQLiteModuleNoop
          400  +      {
          401  +        public SQLiteModuleTest${id}(string name)
          402  +          : base(name)
          403  +        {
          404  +          // do nothing.
          405  +        }
          406  +
          407  +        ///////////////////////////////////////////////////////////////////////
          408  +
          409  +        public override SQLiteErrorCode Create(
          410  +          SQLiteConnection connection,
          411  +          IntPtr pClientData,
          412  +          string\[\] arguments,
          413  +          ref SQLiteVirtualTable table,
          414  +          ref string error
          415  +          )
          416  +        {
          417  +          SQLiteErrorCode rc = DeclareTable(
          418  +            connection, "CREATE TABLE ignored(x);", ref error);
          419  +
          420  +          if (rc != SQLiteErrorCode.Ok)
          421  +            return rc;
          422  +
          423  +          rc = DeclareFunction(connection, -1, "Base64", ref error);
          424  +
          425  +          if (rc != SQLiteErrorCode.Ok)
          426  +            return rc;
          427  +
          428  +          table = new SQLiteVirtualTable(arguments);
          429  +          return SQLiteErrorCode.Ok;
          430  +        }
          431  +
          432  +        ///////////////////////////////////////////////////////////////////////
          433  +
          434  +        public override SQLiteErrorCode Open(
          435  +          SQLiteVirtualTable table,
          436  +          ref SQLiteVirtualTableCursor cursor
          437  +          )
          438  +        {
          439  +          cursor = new SQLiteVirtualTableCursor(table);
          440  +          return SQLiteErrorCode.Ok;
          441  +        }
          442  +
          443  +        ///////////////////////////////////////////////////////////////////////
          444  +
          445  +        public override bool FindFunction(
          446  +          SQLiteVirtualTable table,
          447  +          int argumentCount,
          448  +          string name,
          449  +          ref SQLiteFunction function,
          450  +          ref IntPtr pClientData
          451  +          )
          452  +        {
          453  +          if (argumentCount != 2)
          454  +          {
          455  +            SetTableError(table, String.Format(
          456  +              "no \\"{0}\\" functions accept {1} argument(s)",
          457  +              base.Name, argumentCount));
          458  +
          459  +            return false;
          460  +          }
          461  +
          462  +          if (!String.Equals(name, "Base64",
          463  +              StringComparison.OrdinalIgnoreCase))
          464  +          {
          465  +            SetTableError(table, String.Format(
          466  +              "no \\"{0}\\" functions are named \\"{1}\\"",
          467  +              base.Name, name));
          468  +
          469  +            return false;
          470  +          }
          471  +
          472  +          function = new SQLiteFunction${id}();
          473  +          return true;
          474  +        }
          475  +      }
          476  +
          477  +      /////////////////////////////////////////////////////////////////////////
          478  +
          479  +      public static class Test${id}
          480  +      {
          481  +        public static StringList GetList()
          482  +        {
          483  +          StringList result = new StringList();
          484  +
          485  +          using (SQLiteConnection connection = new SQLiteConnection(
          486  +              "Data Source=${dataSource};"))
          487  +          {
          488  +            connection.Open();
          489  +            connection.CreateModule(new SQLiteModuleTest${id}("mod${id}"));
          490  +
          491  +            try
          492  +            {
          493  +              using (SQLiteCommand command = connection.CreateCommand())
          494  +              {
          495  +                command.CommandText = "[subst ${sql(1)}]";
          496  +                result.Add(String.Format("{0}", command.ExecuteScalar()));
          497  +              }
          498  +            }
          499  +            catch (Exception e)
          500  +            {
          501  +              result.Add(e.Message);
          502  +            }
          503  +
          504  +            try
          505  +            {
          506  +              using (SQLiteCommand command = connection.CreateCommand())
          507  +              {
          508  +                command.CommandText = "[subst ${sql(2)}]";
          509  +                result.Add(String.Format("{0}", command.ExecuteScalar()));
          510  +              }
          511  +            }
          512  +            catch (Exception e)
          513  +            {
          514  +              result.Add(e.Message);
          515  +            }
          516  +
          517  +            try
          518  +            {
          519  +              using (SQLiteCommand command = connection.CreateCommand())
          520  +              {
          521  +                command.CommandText = "[subst ${sql(3)}]";
          522  +                result.Add(String.Format("{0}", command.ExecuteScalar()));
          523  +              }
          524  +            }
          525  +            catch (Exception e)
          526  +            {
          527  +              result.Add(e.Message);
          528  +            }
          529  +
          530  +            try
          531  +            {
          532  +              using (SQLiteCommand command = connection.CreateCommand())
          533  +              {
          534  +                command.CommandText = "[subst ${sql(4)}]";
          535  +                result.Add(String.Format("{0}", command.ExecuteScalar()));
          536  +              }
          537  +            }
          538  +            catch (Exception e)
          539  +            {
          540  +              result.Add(e.Message);
          541  +            }
          542  +
          543  +            connection.Close();
          544  +          }
          545  +
          546  +          return result;
          547  +        }
          548  +
          549  +        ///////////////////////////////////////////////////////////////////////
          550  +
          551  +        public static void Main()
          552  +        {
          553  +          // do nothing.
          554  +        }
          555  +      }
          556  +    }
          557  +  }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]]
          558  +
          559  +  list $code $results \
          560  +      [expr {[info exists errors] ? $errors : ""}] \
          561  +      [expr {$code eq "Ok" ? [catch {
          562  +        object invoke _Dynamic${id}.Test${id} GetList
          563  +      } result] : [set result ""]}] $result
          564  +} -cleanup {
          565  +  cleanupDb $fileName
          566  +
          567  +  unset -nocomplain result code results errors sql dataSource id db fileName
          568  +} -constraints \
          569  +{eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\
          570  +defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \
          571  +[string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\
          572  +\{\} 0 \{\{\} b25l \{SQL logic error or missing database
          573  +unable to use function Base64 in the requested context\} \{SQL logic error or\
          574  +missing database
          575  +no such function: Base65\}\}$}]}
   323    576   
   324    577   ###############################################################################
   325    578   
   326    579   runSQLiteTestEpilogue
   327    580   runTestEpilogue