System.Data.SQLite
Check-in [e1c5eb3fc9]
Not logged in

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

Overview
Comment:Cleanup code related to use of the new sqlite3_close_v2 API.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e1c5eb3fc951bddf7627a059565f5b77dbbd9bf2
User & Date: mistachkin 2012-07-11 04:15:59
Context
2012-07-11
06:47
Add support for URI file names. check-in: cf96d6650f user: mistachkin tags: trunk
04:15
Cleanup code related to use of the new sqlite3_close_v2 API. check-in: e1c5eb3fc9 user: mistachkin tags: trunk
03:37
Update test prologue and epilogue to make sure they unset all variables used prior to using any of them. check-in: 9189c4f757 user: mistachkin tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to SQLite.Interop/src/win/interop.c.

14
15
16
17
18
19
20

21
22
23
24
25
26
27
..
40
41
42
43
44
45
46

47
48
49
50
51
52
53
..
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
...
112
113
114
115
116
117
118
119
120
121

122
123
124
125
126
127
128
...
277
278
279
280
281
282
283



284
285
286
287
288

289
290
291
292
293
294
295

// Additional open flags, we use this one privately
//#define SQLITE_OPEN_SHAREDCACHE      0x01000000

typedef void (*SQLITEUSERFUNC)(sqlite3_context *, int, sqlite3_value **);
typedef void (*SQLITEFUNCFINAL)(sqlite3_context *);


SQLITE_PRIVATE void * sqlite3DbMallocZero_interop(sqlite3 *db, int n)
{
  void *p;
  if (db) {
    sqlite3_mutex_enter(db->mutex);
  }
  p = sqlite3DbMallocZero(db,n);
................................................................................
    sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
  }
  sqlite3DbFree(db,p);
  if (db) {
    sqlite3_mutex_leave(db->mutex);
  }
}


/*
    The goal of this version of close is different than that of sqlite3_close(), and is designed to lend itself better to .NET's non-deterministic finalizers and
    the GC thread.  SQLite will not close a database if statements are open on it -- but for our purposes, we'd rather finalize all active statements
    and forcibly close the database.  The reason is simple -- a lot of people don't Dispose() of their objects correctly and let the garbage collector
    do it.  This leads to unexpected behavior when a user thinks they've closed a database, but it's still open because not all the statements have
    hit the GC yet.
................................................................................
    their memory is freed and can be used for something else.  The GC thread could potentially try and call finalize again on the statement after
    that memory was deallocated.  BAD.  So, what we need to do is make a copy of each statement, and call finalize() on the copy -- so that the original
    statement's memory is preserved, and marked as BAD, but we can still manage to finalize everything and forcibly close the database.  Later when the 
    GC gets around to calling finalize_interop() on the "bad" statement, we detect that and finish deallocating the pointer.
*/
SQLITE_API int WINAPI sqlite3_close_interop(sqlite3 *db)
{
  int ret;
  
#if SQLITE_VERSION_NUMBER >= 3007014
  ret = sqlite3_close_v2(db);
#else
  ret = sqlite3_close(db);

  if (ret == SQLITE_BUSY)
  {
    sqlite3_mutex_enter(db->mutex);

    if (!db->pVdbe)
    {
................................................................................
        ZeroMemory(po, sizeof(Vdbe));
        po->magic = VDBE_MAGIC_DEAD;
      }
    }
    sqlite3_mutex_leave(db->mutex);
    ret = sqlite3_close(db);
  }
#endif

  return ret;

}

SQLITE_API int WINAPI sqlite3_open_interop(const char*filename, int flags, sqlite3 **ppdb)
{
  int ret;
  //int sharedcache = ((flags & SQLITE_OPEN_SHAREDCACHE) != 0);
  //flags &= ~SQLITE_OPEN_SHAREDCACHE;
................................................................................

  return ret;
#endif
}

SQLITE_API int WINAPI sqlite3_reset_interop(sqlite3_stmt *stmt)
{



  int ret;

  if (((Vdbe *)stmt)->magic == VDBE_MAGIC_DEAD) return SQLITE_SCHEMA;
  ret = sqlite3_reset(stmt);
  return ret;

}

SQLITE_API int WINAPI sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, void *pvUser, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEFUNCFINAL funcfinal, int needCollSeq)
{
  int n;

  if (eTextRep == SQLITE_UTF16)







>







 







>







 







<
<

|

|







 







<
<

>







 







>
>
>





>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
..
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
..
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73
74
75
...
112
113
114
115
116
117
118


119
120
121
122
123
124
125
126
127
...
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

// Additional open flags, we use this one privately
//#define SQLITE_OPEN_SHAREDCACHE      0x01000000

typedef void (*SQLITEUSERFUNC)(sqlite3_context *, int, sqlite3_value **);
typedef void (*SQLITEFUNCFINAL)(sqlite3_context *);

#if SQLITE_VERSION_NUMBER < 3007014
SQLITE_PRIVATE void * sqlite3DbMallocZero_interop(sqlite3 *db, int n)
{
  void *p;
  if (db) {
    sqlite3_mutex_enter(db->mutex);
  }
  p = sqlite3DbMallocZero(db,n);
................................................................................
    sqlite3MemdebugSetType(p, MEMTYPE_DB|MEMTYPE_HEAP);
  }
  sqlite3DbFree(db,p);
  if (db) {
    sqlite3_mutex_leave(db->mutex);
  }
}
#endif

/*
    The goal of this version of close is different than that of sqlite3_close(), and is designed to lend itself better to .NET's non-deterministic finalizers and
    the GC thread.  SQLite will not close a database if statements are open on it -- but for our purposes, we'd rather finalize all active statements
    and forcibly close the database.  The reason is simple -- a lot of people don't Dispose() of their objects correctly and let the garbage collector
    do it.  This leads to unexpected behavior when a user thinks they've closed a database, but it's still open because not all the statements have
    hit the GC yet.
................................................................................
    their memory is freed and can be used for something else.  The GC thread could potentially try and call finalize again on the statement after
    that memory was deallocated.  BAD.  So, what we need to do is make a copy of each statement, and call finalize() on the copy -- so that the original
    statement's memory is preserved, and marked as BAD, but we can still manage to finalize everything and forcibly close the database.  Later when the 
    GC gets around to calling finalize_interop() on the "bad" statement, we detect that and finish deallocating the pointer.
*/
SQLITE_API int WINAPI sqlite3_close_interop(sqlite3 *db)
{


#if SQLITE_VERSION_NUMBER >= 3007014
  return sqlite3_close_v2(db);
#else
  int ret = sqlite3_close(db);

  if (ret == SQLITE_BUSY)
  {
    sqlite3_mutex_enter(db->mutex);

    if (!db->pVdbe)
    {
................................................................................
        ZeroMemory(po, sizeof(Vdbe));
        po->magic = VDBE_MAGIC_DEAD;
      }
    }
    sqlite3_mutex_leave(db->mutex);
    ret = sqlite3_close(db);
  }


  return ret;
#endif
}

SQLITE_API int WINAPI sqlite3_open_interop(const char*filename, int flags, sqlite3 **ppdb)
{
  int ret;
  //int sharedcache = ((flags & SQLITE_OPEN_SHAREDCACHE) != 0);
  //flags &= ~SQLITE_OPEN_SHAREDCACHE;
................................................................................

  return ret;
#endif
}

SQLITE_API int WINAPI sqlite3_reset_interop(sqlite3_stmt *stmt)
{
#if SQLITE_VERSION_NUMBER >= 3007014
  return sqlite3_reset(stmt);
#else
  int ret;

  if (((Vdbe *)stmt)->magic == VDBE_MAGIC_DEAD) return SQLITE_SCHEMA;
  ret = sqlite3_reset(stmt);
  return ret;
#endif
}

SQLITE_API int WINAPI sqlite3_create_function_interop(sqlite3 *psql, const char *zFunctionName, int nArg, int eTextRep, void *pvUser, SQLITEUSERFUNC func, SQLITEUSERFUNC funcstep, SQLITEFUNCFINAL funcfinal, int needCollSeq)
{
  int n;

  if (eTextRep == SQLITE_UTF16)