System.Data.SQLite

Check-in [f48d1b0376]
Login

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

Overview
Comment:Never attempt to configure the native SQLite logging interface if the SQLite core library has already been initialized for the process. Fix for ticket [2ce0870fad].
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f48d1b0376b625b8dabfb96a6cf10400d15c63df
User & Date: mistachkin 2011-11-16 03:07:58.514
References
2011-11-16
03:09 Closed ticket [2ce0870fad]: Exception from logging initialization after library initialization plus 2 other changes artifact: 9a35abb7c6 user: mistachkin
Context
2011-11-16
03:18
Add fix for ticket [2ce0870fad] to version history docs. check-in: 20d47a1bed user: mistachkin tags: trunk
03:07
Never attempt to configure the native SQLite logging interface if the SQLite core library has already been initialized for the process. Fix for ticket [2ce0870fad]. check-in: f48d1b0376 user: mistachkin tags: trunk
2011-11-15
05:53
More doc updates for release 77. check-in: 8f2d20133b user: mistachkin tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to System.Data.SQLite/SQLite3.cs.
1048
1049
1050
1051
1052
1053
1054
1055


1056
1057



































1058
1059
1060
1061
1062
1063
1064
    /// log event occurs.  Only one callback may be set.  If NULL is passed,
    /// the logging callback is unregistered.
    /// </summary>
    /// <param name="func">The callback function to invoke.</param>
    /// <returns>Returns a result code</returns>
    internal override int SetLogCallback(SQLiteLogCallback func)
    {
        int rc = UnsafeNativeMethods.sqlite3_config((int)SQLiteConfigOpsEnum.SQLITE_CONFIG_LOG, func, (IntPtr)0);


        return rc;
    }




































    /// <summary>
    /// Helper function to retrieve a column of data from an active statement.
    /// </summary>
    /// <param name="stmt">The statement being step()'d through</param>
    /// <param name="index">The column index to retrieve</param>
    /// <param name="typ">The type of data contained in the column.  If Uninitialized, this function will retrieve the datatype information.</param>







|
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
    /// log event occurs.  Only one callback may be set.  If NULL is passed,
    /// the logging callback is unregistered.
    /// </summary>
    /// <param name="func">The callback function to invoke.</param>
    /// <returns>Returns a result code</returns>
    internal override int SetLogCallback(SQLiteLogCallback func)
    {
        int rc = UnsafeNativeMethods.sqlite3_config(
            (int)SQLiteConfigOpsEnum.SQLITE_CONFIG_LOG, func, (IntPtr)0);

        return rc;
    }

    /// <summary>
    /// Determines if the SQLite core library has been initialized for the
    /// current process.
    /// </summary>
    /// <returns>
    /// A boolean indicating whether or not the SQLite core library has been
    /// initialized for the current process.
    /// </returns>
    internal override bool IsInitialized()
    {
        return StaticIsInitialized();
    }

    /// <summary>
    /// Determines if the SQLite core library has been initialized for the
    /// current process.
    /// </summary>
    /// <returns>
    /// A boolean indicating whether or not the SQLite core library has been
    /// initialized for the current process.
    /// </returns>
    internal static bool StaticIsInitialized()
    {
        //
        // NOTE: This method [ab]uses the fact that SQLite will always
        //       return SQLITE_ERROR for any unknown configuration option
        //       *unless* the SQLite library has already been initialized.
        //       In that case it will always return SQLITE_MISUSE.
        //
        int rc = UnsafeNativeMethods.sqlite3_config(
            (int)SQLiteConfigOpsEnum.SQLITE_CONFIG_NONE, null, (IntPtr)0);

        return (rc == /* SQLITE_MISUSE */ 21);
    }

    /// <summary>
    /// Helper function to retrieve a column of data from an active statement.
    /// </summary>
    /// <param name="stmt">The statement being step()'d through</param>
    /// <param name="index">The column index to retrieve</param>
    /// <param name="typ">The type of data contained in the column.  If Uninitialized, this function will retrieve the datatype information.</param>
Changes to System.Data.SQLite/SQLiteBase.cs.
202
203
204
205
206
207
208

209
210
211
212
213
214
215
    internal abstract void ChangePassword(byte[] newPasswordBytes);

    internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
    internal abstract void SetCommitHook(SQLiteCommitCallback func);
    internal abstract void SetTraceCallback(SQLiteTraceCallback func);
    internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
    internal abstract int SetLogCallback(SQLiteLogCallback func);


    internal abstract int GetCursorForTable(SQLiteStatement stmt, int database, int rootPage);
    internal abstract long GetRowIdForCursor(SQLiteStatement stmt, int cursor);

    internal abstract object GetValue(SQLiteStatement stmt, int index, SQLiteType typ);

    internal abstract bool AutoCommit







>







202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
    internal abstract void ChangePassword(byte[] newPasswordBytes);

    internal abstract void SetUpdateHook(SQLiteUpdateCallback func);
    internal abstract void SetCommitHook(SQLiteCommitCallback func);
    internal abstract void SetTraceCallback(SQLiteTraceCallback func);
    internal abstract void SetRollbackHook(SQLiteRollbackCallback func);
    internal abstract int SetLogCallback(SQLiteLogCallback func);
    internal abstract bool IsInitialized();

    internal abstract int GetCursorForTable(SQLiteStatement stmt, int database, int rootPage);
    internal abstract long GetRowIdForCursor(SQLiteStatement stmt, int cursor);

    internal abstract object GetValue(SQLiteStatement stmt, int index, SQLiteType typ);

    internal abstract bool AutoCommit
320
321
322
323
324
325
326

327
328
329
330
331
332
333
    SharedCache = 0x01000000,
    Default = 0x06,
  }

  // These are the options to the internal sqlite3_config call.
  internal enum SQLiteConfigOpsEnum
  {

    SQLITE_CONFIG_SINGLETHREAD = 1, // nil 
    SQLITE_CONFIG_MULTITHREAD = 2, // nil 
    SQLITE_CONFIG_SERIALIZED = 3, // nil 
    SQLITE_CONFIG_MALLOC = 4, // sqlite3_mem_methods* 
    SQLITE_CONFIG_GETMALLOC = 5, // sqlite3_mem_methods* 
    SQLITE_CONFIG_SCRATCH = 6, // void*, int sz, int N 
    SQLITE_CONFIG_PAGECACHE = 7, // void*, int sz, int N 







>







321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    SharedCache = 0x01000000,
    Default = 0x06,
  }

  // These are the options to the internal sqlite3_config call.
  internal enum SQLiteConfigOpsEnum
  {
    SQLITE_CONFIG_NONE = 0, // nil 
    SQLITE_CONFIG_SINGLETHREAD = 1, // nil 
    SQLITE_CONFIG_MULTITHREAD = 2, // nil 
    SQLITE_CONFIG_SERIALIZED = 3, // nil 
    SQLITE_CONFIG_MALLOC = 4, // sqlite3_mem_methods* 
    SQLITE_CONFIG_GETMALLOC = 5, // sqlite3_mem_methods* 
    SQLITE_CONFIG_SCRATCH = 6, // void*, int sz, int N 
    SQLITE_CONFIG_PAGECACHE = 7, // void*, int sz, int N 
Changes to System.Data.SQLite/SQLiteLog.cs.
107
108
109
110
111
112
113








114
115
116
117
118
119
120
        private static bool _enabled;

        /// <summary>
        /// Initializes the SQLite logging facilities.
        /// </summary>
        public static void Initialize()
        {








            //
            // BUGFIX: To avoid nasty situations where multiple AppDomains are
            //         attempting to initialize and/or shutdown what is really
            //         a shared native resource (i.e. the SQLite core library
            //         is loaded per-process and has only one logging callback,
            //         not one per-AppDomain, which it knows nothing about),
            //         prevent all non-default AppDomains from registering a







>
>
>
>
>
>
>
>







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
        private static bool _enabled;

        /// <summary>
        /// Initializes the SQLite logging facilities.
        /// </summary>
        public static void Initialize()
        {
            //
            // BUFXIX: We cannot initialize the logging interface if the SQLite
            //         core library has already been initialized anywhere in
            //         the process (see ticket [2ce0870fad]).
            //
            if (SQLite3.StaticIsInitialized())
                return;

            //
            // BUGFIX: To avoid nasty situations where multiple AppDomains are
            //         attempting to initialize and/or shutdown what is really
            //         a shared native resource (i.e. the SQLite core library
            //         is loaded per-process and has only one logging callback,
            //         not one per-AppDomain, which it knows nothing about),
            //         prevent all non-default AppDomains from registering a
Changes to Tests/common.eagle.
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
        #
        tputs $::test_channel [appendArgs \
            "==== WARNING: failed to close database \"" $db "\", error: " \
            \n\t $error \n]
      }

      #
      # NOTE: Attempt to delete the test database file now.  For now, all test
      #       database files are stored in the temporary directory.
      #
      set fileName [file join [getTemporaryPath] [file tail $fileName]]





      if {[set code [catch {file delete $fileName} error]]} then {
        #
        # NOTE: We somehow failed to delete the file, report why.
        #
        tputs $::test_channel [appendArgs \
            "==== WARNING: failed to delete database file \"" $fileName \
            "\" during cleanup, error: " \n\t $error \n]






      }

      return $code
    }

    proc reportSQLiteResources { channel {quiet false} } {
      #







|




>
>
>
>
|
|
|
|
|
|
|
>
>
>
>
>
>







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
        #
        tputs $::test_channel [appendArgs \
            "==== WARNING: failed to close database \"" $db "\", error: " \
            \n\t $error \n]
      }

      #
      # NOTE: Build the full path to the database file name.  For now, all test
      #       database files are stored in the temporary directory.
      #
      set fileName [file join [getTemporaryPath] [file tail $fileName]]

      if {[file exists $fileName]} then {
        #
        # NOTE: Attempt to delete the test database file now.
        #
        if {[set code [catch {file delete $fileName} error]]} then {
          #
          # NOTE: We somehow failed to delete the file, report why.
          #
          tputs $::test_channel [appendArgs \
              "==== WARNING: failed to delete database file \"" $fileName \
              "\" during cleanup, error: " \n\t $error \n]
        }
      } else {
        #
        # NOTE: The file does not exist, success!
        #
        set code 0
      }

      return $code
    }

    proc reportSQLiteResources { channel {quiet false} } {
      #
Added Tests/tkt-2ce0870fad.eagle.


































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
###############################################################################
#
# tkt-2ce0870fad.eagle --
#
# Written by Joe Mistachkin.
# Released to the public domain, use at your own risk!
#
###############################################################################

package require Eagle
package require EagleLibrary
package require EagleTest

runTestPrologue

###############################################################################

package require System.Data.SQLite.Test
runSQLiteTestPrologue

###############################################################################

#
# NOTE: Make sure that SQLite core library is completely shutdown prior to
#       starting any of the tests in this file.
#
if {[haveConstraint SQLite]} then {
  object invoke -flags +NonPublic System.Data.SQLite.UnsafeNativeMethods \
      sqlite3_shutdown
}

###############################################################################

for {set i 1} {$i < 3} {incr i} {
  runTest {test [appendArgs tkt-2ce0870fad-1. $i] {logging setup} -setup \
      [getAppDomainPreamble {
    set i {$i}
    set appDomainId($i) {[object invoke AppDomain.CurrentDomain Id]}
    set fileName {[appendArgs tkt-2ce0870fad-1. $i .db]}
  }] -body {
    set appDomainId(3) [object invoke AppDomain.CurrentDomain Id]

    package require EagleLibrary
    package require EagleTest
    package require System.Data.SQLite.Test

    object load -loadtype File [file join [getBinaryDirectory] \
        System.Data.SQLite.dll]

    object invoke System.Data.SQLite.SQLiteLog Initialize

    list $appDomainId($i) $appDomainId(3) [expr {$i == 1 ? \
        $appDomainId($i) != $appDomainId(3) : \
        $appDomainId($i) == $appDomainId(3)}] [setupDb $fileName]
  } -cleanup {
    cleanupDb $fileName

    #
    # NOTE: If this is the primary application domain, skip unsetting the
    #       loop variable because the surrounding [for] command still needs
    #       it.
    #
    if {$i <= 1} then {
      unset -nocomplain i
    }

    unset -nocomplain appDomainId db fileName
  } -constraints {eagle monoBug28 command.sql compile.DATA\
compile.ISOLATED_INTERPRETERS SQLite System.Data.SQLite} -isolationLevel \
[expr {$i == 1 ? "AppDomain" : "Default"}] -match regexp -result \
{^\d+ \d+ True SQLiteConnection#\d+$}}
}

###############################################################################

unset -nocomplain i

###############################################################################

runSQLiteTestEpilogue
runTestEpilogue