Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Make sure that exceptions are never thrown back to native code from user-provided function and collation implementations. Also, log all such caught callback exceptions if the appropriate connection flag is set. Fix for ticket [8a426d12eb]. Pass connection flags into SQLiteFunction binding method and refactor internal interfaces to support this. Change type of _contextDataList (SQLiteFunction) dictionary keys from long to IntPtr. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | logBind |
Files: | files | file ages | folders |
SHA1: |
6136a92dc55489d232794a5e5bee5c7f |
User & Date: | mistachkin 2012-02-19 08:11:39.180 |
References
2012-02-29
| ||
14:55 | • Closed ticket [8a426d12eb]: delegates marked with UnmanagedFunctionPointer (i.e. called from native code) must not throw exceptions plus 2 other changes artifact: 2ec39c6405 user: mistachkin | |
2012-02-19
| ||
13:20 | • Ticket [8a426d12eb]: 2 changes artifact: d499f54003 user: mistachkin | |
Context
2012-02-19
| ||
08:34 | Refactor previous commit to remove the new delegates as they are not strictly required. Also, remove superfluous newData local variable in the StepCallback method. check-in: c43fca0ae6 user: mistachkin tags: logBind | |
08:11 | Make sure that exceptions are never thrown back to native code from user-provided function and collation implementations. Also, log all such caught callback exceptions if the appropriate connection flag is set. Fix for ticket [8a426d12eb]. Pass connection flags into SQLiteFunction binding method and refactor internal interfaces to support this. Change type of _contextDataList (SQLiteFunction) dictionary keys from long to IntPtr. check-in: 6136a92dc5 user: mistachkin tags: logBind | |
03:49 | Add the ability to log all parameter binding activity and refactor the necessary internal interfaces to support this. In the implicit conversion operators to IntPtr for both the SQLiteConnectionHandle and SQLiteStatementHandle classes, return IntPtr.Zero if the object being converted is null. Make sure the SQLiteLog class is not referenced when building for Windows CE. check-in: 20e1e255b6 user: mistachkin tags: logBind | |
Changes
Changes to System.Data.SQLite/SQLite3.cs.
︙ | ︙ | |||
208 209 210 211 212 213 214 | } internal override bool IsOpen() { return (_sql != null); } | | | | | | 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 | } internal override bool IsOpen() { return (_sql != null); } internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) { if (_sql != null) return; _usePool = usePool; if (usePool) { _fileName = strFilename; _sql = SQLiteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion); } if (_sql == null) { IntPtr db; #if !SQLITE_STANDARD int n = UnsafeNativeMethods.sqlite3_open_interop(ToUTF8(strFilename), (int)openFlags, out db); #else int n = UnsafeNativeMethods.sqlite3_open_v2(ToUTF8(strFilename), out db, (int)openFlags, IntPtr.Zero); #endif #if DEBUG Trace.WriteLine(String.Format("Open: {0}", db)); #endif if (n > 0) throw new SQLiteException(n, null); _sql = db; } // Bind functions to this connection. If any previous functions of the same name // were already bound, then the new bindings replace the old. _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); SetTimeout(0); } internal override void ClearPool() { SQLiteConnectionPool.ClearPool(_fileName); } |
︙ | ︙ |
Changes to System.Data.SQLite/SQLite3_UTF16.cs.
︙ | ︙ | |||
84 85 86 87 88 89 90 | if (nbytelen == -1) return Marshal.PtrToStringUni(b); else return Marshal.PtrToStringUni(b, nbytelen / 2); } | | | | | 84 85 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 | if (nbytelen == -1) return Marshal.PtrToStringUni(b); else return Marshal.PtrToStringUni(b, nbytelen / 2); } internal override void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool) { if (_sql != null) return; _usePool = usePool; if (usePool) { _fileName = strFilename; _sql = SQLiteConnectionPool.Remove(strFilename, maxPoolSize, out _poolVersion); } if (_sql == null) { IntPtr db; #if !SQLITE_STANDARD int n = UnsafeNativeMethods.sqlite3_open16_interop(ToUTF8(strFilename), (int)openFlags, out db); #else if ((flags & SQLiteOpenFlagsEnum.Create) == 0 && System.IO.File.Exists(strFilename) == false) throw new SQLiteException((int)SQLiteErrorCode.CantOpen, strFilename); int n = UnsafeNativeMethods.sqlite3_open16(strFilename, out db); #endif #if DEBUG Trace.WriteLine(String.Format("Open: {0}", db)); #endif if (n > 0) throw new SQLiteException(n, null); _sql = db; } _functionsArray = SQLiteFunction.BindFunctions(this, connectionFlags); } internal override void Bind_DateTime(SQLiteStatement stmt, SQLiteConnectionFlags flags, int index, DateTime dt) { switch (_datetimeFormat) { case SQLiteDateFormats.Ticks: |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteBase.cs.
︙ | ︙ | |||
54 55 56 57 58 59 60 | /// Opens a database. /// </summary> /// <remarks> /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection /// to bind all attributed user-defined functions and collating sequences to the new connection. /// </remarks> /// <param name="strFilename">The filename of the database to open. SQLite automatically creates it if it doesn't exist.</param> | > | | | 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | /// Opens a database. /// </summary> /// <remarks> /// Implementers should call SQLiteFunction.BindFunctions() and save the array after opening a connection /// to bind all attributed user-defined functions and collating sequences to the new connection. /// </remarks> /// <param name="strFilename">The filename of the database to open. SQLite automatically creates it if it doesn't exist.</param> /// <param name="connectionFlags">The flags associated with the parent connection object</param> /// <param name="openFlags">The open flags to use when creating the connection</param> /// <param name="maxPoolSize">The maximum size of the pool for the given filename</param> /// <param name="usePool">If true, the connection can be pulled from the connection pool</param> internal abstract void Open(string strFilename, SQLiteConnectionFlags connectionFlags, SQLiteOpenFlagsEnum openFlags, int maxPoolSize, bool usePool); /// <summary> /// Closes the currently-open database. /// </summary> /// <remarks> /// After the database has been closed implemeters should call SQLiteFunction.UnbindFunctions() to deallocate all interop allocated /// memory associated with the user-defined functions and collating sequences tied to the closed connection. /// </remarks> |
︙ | ︙ | |||
391 392 393 394 395 396 397 398 399 400 | LogPreBind = 0x2, /// <summary> /// Enable logging of all bound parameter strongly typed values. /// </summary> LogBind = 0x4, /// <summary> /// Enable all logging. /// </summary> | > > > > > > | | 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 | LogPreBind = 0x2, /// <summary> /// Enable logging of all bound parameter strongly typed values. /// </summary> LogBind = 0x4, /// <summary> /// Enable logging of all exceptions caught from user-provided /// managed code called from native code via delegates. /// </summary> LogCallbackException = 0x8, /// <summary> /// Enable all logging. /// </summary> LogAll = LogPrepare | LogPreBind | LogBind | LogCallbackException, /// <summary> /// The default extra flags for new connections. /// </summary> Default = None } |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteConnection.cs.
︙ | ︙ | |||
937 938 939 940 941 942 943 | flags &= ~SQLiteOpenFlagsEnum.Create; } else { flags |= SQLiteOpenFlagsEnum.ReadWrite; } | | | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 | flags &= ~SQLiteOpenFlagsEnum.Create; } else { flags |= SQLiteOpenFlagsEnum.ReadWrite; } _sql.Open(fileName, _flags, flags, maxPoolSize, usePooling); _binaryGuid = (SQLiteConvert.ToBoolean(FindKey(opts, "BinaryGUID", Boolean.TrueString)) == true); string password = FindKey(opts, "Password", null); if (String.IsNullOrEmpty(password) == false) _sql.SetPassword(System.Text.UTF8Encoding.UTF8.GetBytes(password)); |
︙ | ︙ |
Changes to System.Data.SQLite/SQLiteFunction.cs.
︙ | ︙ | |||
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | { private class AggregateData { internal int _count = 1; internal object _data; } /// <summary> /// The base connection this function is attached to /// </summary> internal SQLiteBase _base; /// <summary> /// Internal array used to keep track of aggregate function context data /// </summary> | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | { private class AggregateData { internal int _count = 1; internal object _data; } ///////////////////////////////////////////////////////////////////////// #region Private Constants /// <summary> /// The error code used for logging exceptions caught in user-provided /// code. /// </summary> private const int COR_E_EXCEPTION = unchecked((int)0x80131500); #endregion ///////////////////////////////////////////////////////////////////////// #region Private Delegate Types /// <summary> /// See the Invoke method of this class. /// </summary> /// <param name="args"> /// See the Invoke method of this class. /// </param> /// <returns> /// See the Invoke method of this class. /// </returns> private delegate object SQLiteFunctionInvokeCallback( object[] args ); ///////////////////////////////////////////////////////////////////////// /// <summary> /// See the Step method of this class. /// </summary> /// <param name="args"> /// See the Step method of this class. /// </param> /// <param name="stepNumber"> /// See the Step method of this class. /// </param> /// <param name="contextData"> /// See the Step method of this class. /// </param> private delegate void SQLiteFunctionStepCallback( object[] args, int stepNumber, ref object contextData ); ///////////////////////////////////////////////////////////////////////// /// <summary> /// See the Final method of this class. /// </summary> /// <param name="contextData"> /// See the Final method of this class. /// </param> /// <returns> /// See the Final method of this class. /// </returns> private delegate object SQLiteFunctionFinalCallback( object contextData ); ///////////////////////////////////////////////////////////////////////// /// <summary> /// See the Compare method of this class. /// </summary> /// <param name="param1"> /// See the Compare method of this class. /// </param> /// <param name="param2"> /// See the Compare method of this class. /// </param> /// <returns> /// See the Compare method of this class. /// </returns> private delegate int SQLiteCollationCompareCallback( string param1, string param2 ); #endregion ///////////////////////////////////////////////////////////////////////// /// <summary> /// The base connection this function is attached to /// </summary> internal SQLiteBase _base; /// <summary> /// Internal array used to keep track of aggregate function context data /// </summary> private Dictionary<IntPtr, AggregateData> _contextDataList; /// <summary> /// The connection flags associated with this object (this should be the /// same value as the flags associated with the parent connection object). /// </summary> private SQLiteConnectionFlags _flags; /// <summary> /// The private instance of the SQLiteFunctionInvokeCallback delegate /// associated with this object. /// </summary> private SQLiteFunctionInvokeCallback _invokeCallback; /// <summary> /// The private instance of the SQLiteFunctionStepCallback delegate /// associated with this object. /// </summary> private SQLiteFunctionStepCallback _stepCallback; /// <summary> /// The private instance of the SQLiteFunctionFinalCallback delegate /// associated with this object. /// </summary> private SQLiteFunctionFinalCallback _finalCallback; /// <summary> /// The private instance of the SQLiteCollationCompareCallback delegate /// associated with this object. /// </summary> private SQLiteCollationCompareCallback _compareCallback; /// <summary> /// Holds a reference to the callback function for user functions /// </summary> private SQLiteCallback _InvokeFunc; /// <summary> /// Holds a reference to the callbakc function for stepping in an aggregate function |
︙ | ︙ | |||
76 77 78 79 80 81 82 | private static List<SQLiteFunctionAttribute> _registeredFunctions; /// <summary> /// Internal constructor, initializes the function's internal variables. /// </summary> protected SQLiteFunction() { | | | 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | private static List<SQLiteFunctionAttribute> _registeredFunctions; /// <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 |
︙ | ︙ | |||
123 124 125 126 127 128 129 | { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// IDisposable disp; | | > > > > > > > < | 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 | { //////////////////////////////////// // dispose managed resources here... //////////////////////////////////// IDisposable disp; foreach (KeyValuePair<IntPtr, AggregateData> kv in _contextDataList) { disp = kv.Value._data as IDisposable; if (disp != null) disp.Dispose(); } _contextDataList.Clear(); _contextDataList = null; _flags = SQLiteConnectionFlags.None; _invokeCallback = null; _stepCallback = null; _finalCallback = null; _compareCallback = null; _InvokeFunc = null; _StepFunc = null; _FinalFunc = null; _CompareFunc = null; _base = null; } ////////////////////////////////////// // release unmanaged resources here... ////////////////////////////////////// disposed = true; |
︙ | ︙ | |||
346 347 348 349 350 351 352 353 354 355 356 357 358 | _base.ReturnBlob(context, (byte[])returnValue); return; } } /// <summary> /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. /// </summary> /// <param name="context">A raw context pointer</param> /// <param name="nArgs">Number of arguments passed in</param> /// <param name="argsptr">A pointer to the array of arguments</param> internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr) { | > > > > > | | > | > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > | | > > | > > > > > > > | > > > | > > > > > > > > > > | > > | > > > | > > | > > | | | | | | > > > | | | | > | | | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > < > > > > | > > > > > | > | | | | | > > > | | | > > | | > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 | _base.ReturnBlob(context, (byte[])returnValue); return; } } /// <summary> /// Internal scalar callback function, which wraps the raw context pointer and calls the virtual Invoke() method. /// Does nothing if there is no invoke callback configured. WARNING: Must not throw exceptions. /// </summary> /// <param name="context">A raw context pointer</param> /// <param name="nArgs">Number of arguments passed in</param> /// <param name="argsptr">A pointer to the array of arguments</param> internal void ScalarCallback(IntPtr context, int nArgs, IntPtr argsptr) { if (_invokeCallback != null) { try { _context = context; SetReturnValue(context, _invokeCallback(ConvertParams(nArgs, argsptr))); /* throw */ } #if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == SQLiteConnectionFlags.LogCallbackException) { SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( "Caught exception in {0} callback: {1}", typeof(SQLiteFunctionInvokeCallback), e)); /* throw */ } } catch { // do nothing. } } #else catch /* NOTE: Must catch ALL. */ { // do nothing (Windows CE). } #endif } } /// <summary> /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. /// Does nothing and returns zero if there is no compare callback configured. WARNING: Must not throw exceptions. /// </summary> /// <param name="ptr">Not used</param> /// <param name="len1">Length of the string pv1</param> /// <param name="ptr1">Pointer to the first string to compare</param> /// <param name="len2">Length of the string pv2</param> /// <param name="ptr2">Pointer to the second string to compare</param> /// <returns>Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater /// than the second. Returns 0 if there is no callback wrapper configured or an exception is caught.</returns> internal int CompareCallback(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) { if (_compareCallback != null) { try { return _compareCallback(SQLiteConvert.UTF8ToString(ptr1, len1), SQLiteConvert.UTF8ToString(ptr2, len2)); /* throw */ } #if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == SQLiteConnectionFlags.LogCallbackException) { SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( "Caught exception in {0} callback: {1}", typeof(SQLiteCollationCompareCallback), e)); /* throw */ } } catch { // do nothing. } } #else catch /* NOTE: Must catch ALL. */ { // do nothing (Windows CE). } #endif } return 0; } /// <summary> /// Internal collation sequence function, which wraps up the raw string pointers and executes the Compare() virtual function. /// Does nothing and returns zero if there is no compare callback configured. WARNING: Must not throw exceptions. /// </summary> /// <param name="ptr">Not used</param> /// <param name="len1">Length of the string pv1</param> /// <param name="ptr1">Pointer to the first string to compare</param> /// <param name="len2">Length of the string pv2</param> /// <param name="ptr2">Pointer to the second string to compare</param> /// <returns>Returns -1 if the first string is less than the second. 0 if they are equal, or 1 if the first string is greater /// than the second. Returns 0 if there is no callback wrapper configured or an exception is caught.</returns> internal int CompareCallback16(IntPtr ptr, int len1, IntPtr ptr1, int len2, IntPtr ptr2) { if (_compareCallback != null) { try { return _compareCallback(SQLite3_UTF16.UTF16ToString(ptr1, len1), SQLite3_UTF16.UTF16ToString(ptr2, len2)); /* throw */ } #if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == SQLiteConnectionFlags.LogCallbackException) { SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( "Caught exception in {0} callback: {1}", typeof(SQLiteCollationCompareCallback), e)); /* throw */ } } catch { // do nothing. } } #else catch /* NOTE: Must catch ALL. */ { // do nothing (Windows CE). } #endif } return 0; } /// <summary> /// The internal aggregate Step function callback, which wraps the raw context pointer and calls the virtual Step() method. /// Does nothing if there is no step callback configured. WARNING: Must not throw exceptions. /// </summary> /// <remarks> /// This function takes care of doing the lookups and getting the important information put together to call the Step() function. /// That includes pulling out the user's contextData and updating it after the call is made. We use a sorted list for this so /// binary searches can be done to find the data. /// </remarks> /// <param name="context">A raw context pointer</param> /// <param name="nArgs">Number of arguments passed in</param> /// <param name="argsptr">A pointer to the array of arguments</param> internal void StepCallback(IntPtr context, int nArgs, IntPtr argsptr) { if (_stepCallback != null) { try { AggregateData data = null; if (_base != null) { IntPtr nAux = _base.AggregateContext(context); if ((_contextDataList != null) && !_contextDataList.TryGetValue(nAux, out data)) { data = new AggregateData(); _contextDataList[nAux] = data; } } AggregateData newData = (data != null) ? data : new AggregateData(); try { _context = context; _stepCallback(ConvertParams(nArgs, argsptr), newData._count, ref newData._data); /* throw */ } finally { newData._count++; } } #if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == SQLiteConnectionFlags.LogCallbackException) { SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( "Caught exception in {0} callback: {1}", typeof(SQLiteFunctionStepCallback), e)); /* throw */ } } catch { // do nothing. } } #else catch /* NOTE: Must catch ALL. */ { // do nothing (Windows CE). } #endif } } /// <summary> /// An internal aggregate Final function callback, which wraps the context pointer and calls the virtual Final() method. /// Does nothing if there is no final callback configured. WARNING: Must not throw exceptions. /// </summary> /// <param name="context">A raw context pointer</param> internal void FinalCallback(IntPtr context) { if (_finalCallback != null) { try { object obj = null; if (_base != null) { IntPtr n = _base.AggregateContext(context); AggregateData aggData; if ((_contextDataList != null) && _contextDataList.TryGetValue(n, out aggData)) { obj = aggData._data; _contextDataList.Remove(n); } } try { _context = context; SetReturnValue(context, _finalCallback(obj)); /* throw */ } finally { IDisposable disp = obj as IDisposable; if (disp != null) disp.Dispose(); /* throw */ } } #if !PLATFORM_COMPACTFRAMEWORK catch (Exception e) /* NOTE: Must catch ALL. */ { try { if ((_flags & SQLiteConnectionFlags.LogCallbackException) == SQLiteConnectionFlags.LogCallbackException) { SQLiteLog.LogMessage(COR_E_EXCEPTION, String.Format( "Caught exception in {0} callback: {1}", typeof(SQLiteFunctionFinalCallback), e)); /* throw */ } } catch { // do nothing. } } #else catch /* NOTE: Must catch ALL. */ { // do nothing (Windows CE). } #endif } } /// <summary> /// Using reflection, enumerate all assemblies in the current appdomain looking for classes that /// have a SQLiteFunctionAttribute attribute, and registering them accordingly. /// </summary> #if !PLATFORM_COMPACTFRAMEWORK |
︙ | ︙ | |||
536 537 538 539 540 541 542 543 | /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns> | > | > > > > > > | 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 | /// as the connection (UTF-8 or UTF-16). /// </summary> /// <remarks> /// The wrapper functions that interop with SQLite will create a unique cookie value, which internally is a pointer to /// all the wrapped callback functions. The interop function uses it to map CDecl callbacks to StdCall callbacks. /// </remarks> /// <param name="sqlbase">The base object on which the functions are to bind</param> /// <param name="flags">The flags associated with the parent connection object</param> /// <returns>Returns an array of functions which the connection object should retain until the connection is closed.</returns> internal static SQLiteFunction[] BindFunctions(SQLiteBase sqlbase, SQLiteConnectionFlags flags) { SQLiteFunction f; List<SQLiteFunction> lFunctions = new List<SQLiteFunction>(); foreach (SQLiteFunctionAttribute pr in _registeredFunctions) { f = (SQLiteFunction)Activator.CreateInstance(pr._instanceType); f._base = sqlbase; f._flags = flags; f._invokeCallback = f.Invoke; f._stepCallback = f.Step; f._finalCallback = f.Final; f._compareCallback = f.Compare; f._InvokeFunc = (pr.FuncType == FunctionType.Scalar) ? new SQLiteCallback(f.ScalarCallback) : null; f._StepFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteCallback(f.StepCallback) : null; f._FinalFunc = (pr.FuncType == FunctionType.Aggregate) ? new SQLiteFinalCallback(f.FinalCallback) : null; f._CompareFunc = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback) : null; f._CompareFunc16 = (pr.FuncType == FunctionType.Collation) ? new SQLiteCollation(f.CompareCallback16) : null; if (pr.FuncType != FunctionType.Collation) |
︙ | ︙ |