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 |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
3e1da60858edc922f4d69435e2eefa36 |
User & Date: | mistachkin 2013-07-01 10:16:18.452 |
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
Changes to System.Data.SQLite/SQLite3.cs.
︙ | ︙ | |||
1731 1732 1733 1734 1735 1736 1737 | { return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1); } #if INTEROP_VIRTUAL_TABLE /// <summary> /// Calls the native SQLite core library in order to declare a virtual table | | > | 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 | { return UnsafeNativeMethods.sqlite3_aggregate_context(context, 1); } #if INTEROP_VIRTUAL_TABLE /// <summary> /// Calls the native SQLite core library in order to declare a virtual table /// in response to a call into the <see cref="ISQLiteNativeModule.xCreate" /> /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods. /// </summary> /// <param name="module"> /// The virtual table module that is to be responsible for the virtual table /// being declared. /// </param> /// <param name="strSql"> /// The string containing the SQL statement describing the virtual table to |
︙ | ︙ | |||
1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 | if (pSql != IntPtr.Zero) { SQLiteMemory.Free(pSql); pSql = IntPtr.Zero; } } } #endif /// <summary> /// Enables or disabled extension loading by SQLite. /// </summary> /// <param name="bOnOff"> /// True to enable loading of extensions, false to disable. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 | if (pSql != IntPtr.Zero) { SQLiteMemory.Free(pSql); pSql = IntPtr.Zero; } } } /// <summary> /// Calls the native SQLite core library in order to declare a virtual table /// function in response to a call into the <see cref="ISQLiteNativeModule.xCreate" /> /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods. /// </summary> /// <param name="module"> /// The virtual table module that is to be responsible for the virtual table /// function being declared. /// </param> /// <param name="argumentCount"> /// The number of arguments to the function being declared. /// </param> /// <param name="name"> /// The name of the function being declared. /// </param> /// <param name="error"> /// Upon success, the contents of this parameter are undefined. Upon failure, /// it should contain an appropriate error message. /// </param> /// <returns> /// A standard SQLite return code. /// </returns> internal override SQLiteErrorCode DeclareVirtualFunction( SQLiteModule module, int argumentCount, string name, ref string error ) { if (_sql == null) { error = "connection has an invalid handle"; return SQLiteErrorCode.Error; } IntPtr pName = IntPtr.Zero; try { pName = SQLiteString.Utf8IntPtrFromString(name); SQLiteErrorCode n = UnsafeNativeMethods.sqlite3_overload_function( _sql, pName, argumentCount); if (n != SQLiteErrorCode.Ok) error = GetLastError(); return n; } finally { if (pName != IntPtr.Zero) { SQLiteMemory.Free(pName); pName = IntPtr.Zero; } } } #endif /// <summary> /// Enables or disabled extension loading by SQLite. /// </summary> /// <param name="bOnOff"> /// True to enable loading of extensions, false to disable. |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteBase.cs.
︙ | ︙ | |||
233 234 235 236 237 238 239 | /// The module object previously passed to the <see cref="CreateModule" /> /// method. /// </param> internal abstract void DisposeModule(SQLiteModule module); /// <summary> /// Calls the native SQLite core library in order to declare a virtual table | | > > > > > > > > > > > > > > > > > > > > > > > > > | 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 | /// The module object previously passed to the <see cref="CreateModule" /> /// method. /// </param> internal abstract void DisposeModule(SQLiteModule module); /// <summary> /// Calls the native SQLite core library in order to declare a virtual table /// in response to a call into the <see cref="ISQLiteNativeModule.xCreate" /> /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods. /// </summary> /// <param name="module"> /// The virtual table module that is to be responsible for the virtual table /// being declared. /// </param> /// <param name="strSql"> /// The string containing the SQL statement describing the virtual table to /// be declared. /// </param> /// <param name="error"> /// Upon success, the contents of this parameter are undefined. Upon failure, /// it should contain an appropriate error message. /// </param> /// <returns> /// A standard SQLite return code. /// </returns> internal abstract SQLiteErrorCode DeclareVirtualTable(SQLiteModule module, string strSql, ref string error); /// <summary> /// Calls the native SQLite core library in order to declare a virtual table /// function in response to a call into the <see cref="ISQLiteNativeModule.xCreate" /> /// or <see cref="ISQLiteNativeModule.xConnect" /> virtual table methods. /// </summary> /// <param name="module"> /// The virtual table module that is to be responsible for the virtual table /// function being declared. /// </param> /// <param name="argumentCount"> /// The number of arguments to the function being declared. /// </param> /// <param name="name"> /// The name of the function being declared. /// </param> /// <param name="error"> /// Upon success, the contents of this parameter are undefined. Upon failure, /// it should contain an appropriate error message. /// </param> /// <returns> /// A standard SQLite return code. /// </returns> internal abstract SQLiteErrorCode DeclareVirtualFunction(SQLiteModule module, int argumentCount, string name, ref string error); #endif /// <summary> /// Enables or disabled extension loading by SQLite. /// </summary> /// <param name="bOnOff"> /// True to enable loading of extensions, false to disable. |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteFunction.cs.
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | /// <summary> /// Internal constructor, initializes the function's internal variables. /// </summary> protected SQLiteFunction() { _contextDataList = new Dictionary<IntPtr, AggregateData>(); } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable Members /// <summary> /// Disposes of any active contextData variables that were not automatically cleaned up. Sometimes this can happen if /// someone closes the connection while a DataReader is open. | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | /// <summary> /// Internal constructor, initializes the function's internal variables. /// </summary> protected SQLiteFunction() { _contextDataList = new Dictionary<IntPtr, AggregateData>(); } /// <summary> /// Constructs an instance of this class using the specified data-type /// conversion parameters. /// </summary> /// <param name="format"> /// The DateTime format to be used when converting string values to a /// DateTime and binding DateTime parameters. /// </param> /// <param name="kind"> /// The <see cref="DateTimeKind" /> to be used when creating DateTime /// values. /// </param> /// <param name="formatString"> /// The format string to be used when parsing and formatting DateTime /// values. /// </param> /// <param name="utf16"> /// Non-zero to create a UTF-16 data-type conversion context; otherwise, /// a UTF-8 data-type conversion context will be created. /// </param> protected SQLiteFunction( SQLiteDateFormats format, DateTimeKind kind, string formatString, bool utf16 ) : this() { if (utf16) _base = new SQLite3_UTF16(format, kind, formatString, IntPtr.Zero, null, false); else _base = new SQLite3(format, kind, formatString, IntPtr.Zero, null, false); } /////////////////////////////////////////////////////////////////////////////////////////////// #region IDisposable Members /// <summary> /// Disposes of any active contextData variables that were not automatically cleaned up. Sometimes this can happen if /// someone closes the connection while a DataReader is open. |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteModule.cs.
︙ | ︙ | |||
5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 | /// <summary> /// This field is used to store the virtual table cursor instances /// associated with this module. The native pointer to the /// sqlite3_vtab_cursor derived structure is used to key into this /// collection. /// </summary> private Dictionary<IntPtr, SQLiteVirtualTableCursor> cursors; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// <summary> /// Constructs an instance of this class. /// </summary> /// <param name="name"> /// The name of the module. This parameter cannot be null. /// </param> public SQLiteModule(string name) { if (name == null) throw new ArgumentNullException("name"); this.name = name; this.tables = new Dictionary<IntPtr, SQLiteVirtualTable>(); this.cursors = new Dictionary<IntPtr, SQLiteVirtualTableCursor>(); } #endregion /////////////////////////////////////////////////////////////////////// #region Internal Methods /// <summary> | > > > > > > > > > > > | 5174 5175 5176 5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 5188 5189 5190 5191 5192 5193 5194 5195 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 | /// <summary> /// This field is used to store the virtual table cursor instances /// associated with this module. The native pointer to the /// sqlite3_vtab_cursor derived structure is used to key into this /// collection. /// </summary> private Dictionary<IntPtr, SQLiteVirtualTableCursor> cursors; /////////////////////////////////////////////////////////////////////// /// <summary> /// This field is used to store the virtual table function instances /// associated with this module. The case-insensitive function name /// and the number of arguments (with -1 meaning "any") are used to /// construct the string that is used to key into this collection. /// </summary> private Dictionary<string, SQLiteFunction> functions; #endregion /////////////////////////////////////////////////////////////////////// #region Public Constructors /// <summary> /// Constructs an instance of this class. /// </summary> /// <param name="name"> /// The name of the module. This parameter cannot be null. /// </param> public SQLiteModule(string name) { if (name == null) throw new ArgumentNullException("name"); this.name = name; this.tables = new Dictionary<IntPtr, SQLiteVirtualTable>(); this.cursors = new Dictionary<IntPtr, SQLiteVirtualTableCursor>(); this.functions = new Dictionary<string, SQLiteFunction>(); } #endregion /////////////////////////////////////////////////////////////////////// #region Internal Methods /// <summary> |
︙ | ︙ | |||
5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 5795 5796 5797 5798 | return pCursor; } #endregion /////////////////////////////////////////////////////////////////////// #region Table Declaration Helper Methods /// <summary> /// Attempts to declare the schema for the virtual table using the /// specified database connection. /// </summary> /// <param name="connection"> /// The <see cref="SQLiteConnection" /> object instance to use when | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5796 5797 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 5818 5819 5820 5821 5822 5823 5824 5825 5826 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 | return pCursor; } #endregion /////////////////////////////////////////////////////////////////////// #region Function Lookup Methods /// <summary> /// Deterimines the key that should be used to identify and store the /// function instance for the virtual table (i.e. to be returned via /// the <see cref="ISQLiteNativeModule.xFindFunction" /> method). /// </summary> /// <param name="argumentCount"> /// The number of arguments to the virtual table function. /// </param> /// <param name="name"> /// The name of the virtual table function. /// </param> /// <param name="function"> /// The <see cref="SQLiteFunction" /> object instance associated with /// this virtual table function. /// </param> /// <returns> /// The string that should be used to identify and store the virtual /// table function instance. This method cannot return null. If null /// is returned from this method, the behavior is undefined. /// </returns> protected virtual string GetFunctionKey( int argumentCount, string name, SQLiteFunction function ) { return String.Format("{0}:{1}", argumentCount, name); } #endregion /////////////////////////////////////////////////////////////////////// #region Table Declaration Helper Methods /// <summary> /// Attempts to declare the schema for the virtual table using the /// specified database connection. /// </summary> /// <param name="connection"> /// The <see cref="SQLiteConnection" /> object instance to use when |
︙ | ︙ | |||
5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 | error = "connection has invalid handle"; return SQLiteErrorCode.Error; } return sqliteBase.DeclareVirtualTable(this, sql, ref error); } #endregion /////////////////////////////////////////////////////////////////////// #region Error Handling Helper Methods /// <summary> /// Arranges for the specified error message to be placed into the /// zErrMsg field of a sqlite3_vtab derived structure, freeing the | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 | error = "connection has invalid handle"; return SQLiteErrorCode.Error; } return sqliteBase.DeclareVirtualTable(this, sql, ref error); } #endregion /////////////////////////////////////////////////////////////////////// #region Function Declaration Helper Methods protected virtual SQLiteErrorCode DeclareFunction( SQLiteConnection connection, int argumentCount, string name, ref string error ) { if (connection == null) { error = "invalid connection"; return SQLiteErrorCode.Error; } SQLiteBase sqliteBase = connection._sql; if (sqliteBase == null) { error = "connection has invalid handle"; return SQLiteErrorCode.Error; } return sqliteBase.DeclareVirtualFunction( this, argumentCount, name, ref error); } #endregion /////////////////////////////////////////////////////////////////////// #region Error Handling Helper Methods /// <summary> /// Arranges for the specified error message to be placed into the /// zErrMsg field of a sqlite3_vtab derived structure, freeing the |
︙ | ︙ | |||
7036 7037 7038 7039 7040 7041 7042 7043 7044 7045 | { try { SQLiteVirtualTable table = TableFromIntPtr(pVtab); if (table != null) { SQLiteFunction function = null; if (FindFunction( | > < < | > > > > | 7109 7110 7111 7112 7113 7114 7115 7116 7117 7118 7119 7120 7121 7122 7123 7124 7125 7126 7127 7128 7129 7130 7131 7132 7133 7134 7135 | { try { SQLiteVirtualTable table = TableFromIntPtr(pVtab); if (table != null) { string name = SQLiteString.StringFromUtf8IntPtr(zName); SQLiteFunction function = null; if (FindFunction( table, nArg, name, ref function, ref pClientData)) { if (function != null) { string key = GetFunctionKey(nArg, name, function); functions[key] = function; callback = function.ScalarCallback; return 1; } else { SetTableError(pVtab, "no function was created"); } } |
︙ | ︙ | |||
7790 7791 7792 7793 7794 7795 7796 | /// <see cref="Dispose()" /> method. Zero if this method is being /// called from the finalizer. /// </param> protected virtual void Dispose(bool disposing) { if (!disposed) { | | < > | | | | > > > | 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 | /// <see cref="Dispose()" /> method. Zero if this method is being /// called from the finalizer. /// </param> protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// if (functions != null) functions.Clear(); } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// try { |
︙ | ︙ |
Changes to System.Data.SQLite/UnsafeNativeMethods.cs.
︙ | ︙ | |||
986 987 988 989 990 991 992 993 994 995 996 997 998 999 | [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_load_extension( IntPtr db, byte[] fileName, byte[] procName, ref IntPtr pError); #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] #else [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] #endif internal static extern SQLiteErrorCode sqlite3_win32_set_directory(uint type, string value); | > > > > > > > | 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 | [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_load_extension( IntPtr db, byte[] fileName, byte[] procName, ref IntPtr pError); #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl)] #else [DllImport(SQLITE_DLL)] #endif internal static extern SQLiteErrorCode sqlite3_overload_function(IntPtr db, IntPtr zName, int nArgs); #if !PLATFORM_COMPACTFRAMEWORK [DllImport(SQLITE_DLL, CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Unicode)] #else [DllImport(SQLITE_DLL, CharSet = CharSet.Unicode)] #endif internal static extern SQLiteErrorCode sqlite3_win32_set_directory(uint type, string value); |
︙ | ︙ |
Changes to Tests/vtab.eagle.
︙ | ︙ | |||
16 17 18 19 20 21 22 | ############################################################################### package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### | | | 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | ############################################################################### package require System.Data.SQLite.Test runSQLiteTestPrologue ############################################################################### runTest {test vtab-1.1 {basic virtual table support} -setup { setupDb [set fileName vtab-1.1.db] } -body { set id [object invoke Interpreter.GetActive NextId] set dataSource [file join [getDatabaseDirectory] $fileName] set sql { \ CREATE VIRTUAL TABLE t${id} USING mod${id}; \ |
︙ | ︙ | |||
316 317 318 319 320 321 322 323 324 325 326 327 | unset -nocomplain result code results errors sql dataSource id db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\ defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \ [string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\ \{\} 0 \{1 2 3 4 5 Error \{SQL logic error or missing database virtual table "t\d+" is read-only\}\}$}]} ############################################################################### runSQLiteTestEpilogue runTestEpilogue | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | unset -nocomplain result code results errors sql dataSource id db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\ defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \ [string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\ \{\} 0 \{1 2 3 4 5 Error \{SQL logic error or missing database virtual table "t\d+" is read-only\}\}$}]} ############################################################################### runTest {test vtab-1.4 {virtual table function support} -setup { setupDb [set fileName vtab-1.4.db] } -body { set id [object invoke Interpreter.GetActive NextId] set dataSource [file join [getDatabaseDirectory] $fileName] set sql(1) { \ CREATE VIRTUAL TABLE t${id} USING mod${id}; \ } set sql(2) { \ SELECT Base64(x, CAST('one' AS BLOB)) FROM t${id}; \ } set sql(3) { \ SELECT Base64(x, CAST('one' AS BLOB), 'two') FROM t${id}; \ } set sql(4) { \ SELECT Base65(x, CAST('one' AS BLOB)) FROM t${id}; \ } unset -nocomplain results errors set code [compileCSharpWith [subst { using System; using System.Data.SQLite; using Eagle._Containers.Public; namespace _Dynamic${id} { public class SQLiteFunction${id} : SQLiteFunction { public SQLiteFunction${id}() : base(SQLiteDateFormats.Default, DateTimeKind.Unspecified, null, false) { // do nothing. } /////////////////////////////////////////////////////////////////////// public override object Invoke( object\[\] args ) { if (args == null) return null; if (args.Length != 2) return new ArgumentException(String.Format( "need exactly two arguments, got {0}", args.Length)); object arg = args\[1\]; if (arg == null) return String.Empty; Type type = arg.GetType(); if (type == typeof(DBNull)) return String.Empty; if (type != typeof(byte\[\])) return new ArgumentException(String.Format( "argument must be byte array, got {0}", type)); return Convert.ToBase64String((byte\[\]) arg); } } ///////////////////////////////////////////////////////////////////////// public sealed class SQLiteModuleTest${id} : SQLiteModuleNoop { public SQLiteModuleTest${id}(string name) : base(name) { // do nothing. } /////////////////////////////////////////////////////////////////////// public override SQLiteErrorCode Create( SQLiteConnection connection, IntPtr pClientData, string\[\] arguments, ref SQLiteVirtualTable table, ref string error ) { SQLiteErrorCode rc = DeclareTable( connection, "CREATE TABLE ignored(x);", ref error); if (rc != SQLiteErrorCode.Ok) return rc; rc = DeclareFunction(connection, -1, "Base64", ref error); if (rc != SQLiteErrorCode.Ok) return rc; table = new SQLiteVirtualTable(arguments); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// public override SQLiteErrorCode Open( SQLiteVirtualTable table, ref SQLiteVirtualTableCursor cursor ) { cursor = new SQLiteVirtualTableCursor(table); return SQLiteErrorCode.Ok; } /////////////////////////////////////////////////////////////////////// public override bool FindFunction( SQLiteVirtualTable table, int argumentCount, string name, ref SQLiteFunction function, ref IntPtr pClientData ) { if (argumentCount != 2) { SetTableError(table, String.Format( "no \\"{0}\\" functions accept {1} argument(s)", base.Name, argumentCount)); return false; } if (!String.Equals(name, "Base64", StringComparison.OrdinalIgnoreCase)) { SetTableError(table, String.Format( "no \\"{0}\\" functions are named \\"{1}\\"", base.Name, name)); return false; } function = new SQLiteFunction${id}(); return true; } } ///////////////////////////////////////////////////////////////////////// public static class Test${id} { public static StringList GetList() { StringList result = new StringList(); using (SQLiteConnection connection = new SQLiteConnection( "Data Source=${dataSource};")) { connection.Open(); connection.CreateModule(new SQLiteModuleTest${id}("mod${id}")); try { using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = "[subst ${sql(1)}]"; result.Add(String.Format("{0}", command.ExecuteScalar())); } } catch (Exception e) { result.Add(e.Message); } try { using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = "[subst ${sql(2)}]"; result.Add(String.Format("{0}", command.ExecuteScalar())); } } catch (Exception e) { result.Add(e.Message); } try { using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = "[subst ${sql(3)}]"; result.Add(String.Format("{0}", command.ExecuteScalar())); } } catch (Exception e) { result.Add(e.Message); } try { using (SQLiteCommand command = connection.CreateCommand()) { command.CommandText = "[subst ${sql(4)}]"; result.Add(String.Format("{0}", command.ExecuteScalar())); } } catch (Exception e) { result.Add(e.Message); } connection.Close(); } return result; } /////////////////////////////////////////////////////////////////////// public static void Main() { // do nothing. } } } }] true true true results errors [list System.Data.SQLite.dll Eagle.dll]] list $code $results \ [expr {[info exists errors] ? $errors : ""}] \ [expr {$code eq "Ok" ? [catch { object invoke _Dynamic${id}.Test${id} GetList } result] : [set result ""]}] $result } -cleanup { cleanupDb $fileName unset -nocomplain result code results errors sql dataSource id db fileName } -constraints \ {eagle monoBug28 command.sql compile.DATA SQLite System.Data.SQLite\ defineConstant.System.Data.SQLite.INTEROP_VIRTUAL_TABLE} -match regexp -result \ [string map [list \n \r\n] {^Ok System#CodeDom#Compiler#CompilerResults#\d+\ \{\} 0 \{\{\} b25l \{SQL logic error or missing database unable to use function Base64 in the requested context\} \{SQL logic error or\ missing database no such function: Base65\}\}$}]} ############################################################################### runSQLiteTestEpilogue runTestEpilogue |